Tests often check whether an error is returned for invalid input.

error check An error check can test both the successful result and the error status without crashing the program.

Error Checks

parts
error_checks.go
Replay: real traced execution (multi-file project)
package main

import (
	"errors"
	"fmt"
)

func divide(total int, parts int) (int, error) {
	if parts == 0 {
		return 0, errors.New("parts must not be zero")
	}
	return total / parts, nil
}

func main() {
	var parts = 2
	value, err := divide(10, parts)
	hasError := err != nil
	status := "pass"
	if hasError {
		status = "handled"
	}

	fmt.Println("parts=", parts)
	fmt.Println("value=", value)
	fmt.Println("hasError=", hasError)
	fmt.Println("status=", status)
}
package main

import (
	"errors"
	"fmt"
)

func divide(total int, parts int) (int, error) {
	if parts == 0 {
		return 0, errors.New("parts must not be zero")
	}
	return total / parts, nil
}

func main() {
	var parts = 0
	value, err := divide(10, parts)
	hasError := err != nil
	status := "pass"
	if hasError {
		status = "handled"
	}

	fmt.Println("parts=", parts)
	fmt.Println("value=", value)
	fmt.Println("hasError=", hasError)
	fmt.Println("status=", status)
}
package main

import (
	"errors"
	"fmt"
)

func divide(total int, parts int) (int, error) {
	if parts == 0 {
		return 0, errors.New("parts must not be zero")
	}
	return total / parts, nil
}

func main() {
	var parts = 5
	value, err := divide(10, parts)
	hasError := err != nil
	status := "pass"
	if hasError {
		status = "handled"
	}

	fmt.Println("parts=", parts)
	fmt.Println("value=", value)
	fmt.Println("hasError=", hasError)
	fmt.Println("status=", status)
}
  1. parts ← 2

    15func main() {16  var parts→ 2 = 2 //@parts=0, 517  value, err := divide(10, parts2)18  hasError := err != nil
  2. func divide(total int, parts int) (int, error)

    8func divide(total10 int, parts2 int) (int, error) {9  if parts == 0 {10    return 0, errors.New("parts must not be zero")11  }12  return total10 / parts2, nil13}
  3. value ← 5, err ← <nil>, hasError ← false, status ← "pass"

    16  var parts = 2 //@parts=0, 517  value→ 5, err→ <nil> := divide(10, parts2)18  hasError→ false := err<nil> != nil19  status→ "pass" := "pass"20  if hasError {21    status = "handled"22  }2324  fmt.Println("parts=", parts2)25  fmt.Println("value=", value5)26  fmt.Println("hasError=", hasErrorfalse)27  fmt.Println("status=", status"pass")28}
    outputparts= 2
    value= 5
    hasError= false
    status= pass
  1. parts ← 0

    15func main() {16  var parts→ 0 = 017  value, err := divide(10, parts0)18  hasError := err != nil
  2. func divide(total int, parts int) (int, error)

    8func divide(total10 int, parts0 int) (int, error) {9  if parts == 0 {
  3. if parts == 0

    8func divide(total int, parts int) (int, error) {9  if parts0 == 0 {10    return 0, errors.New("parts must not be zero")11  }
  4. value ← 0, err ← &errors.errorString{s:"parts must not be zero"}

    16var parts = 017value→ 0, err→ &errors.errorString{s:"parts must not be zero"} := divide(10, parts0)18hasError→ true := err&errors.errorString{s:"parts must not be zero"} != nil19status→ "pass" := "pass"20if hasError {
  5. status ← "handled"

    19status := "pass"20if hasErrortrue {21  status→ "handled" = "handled"22}
  6. fmt.Println("parts=", parts)

    24  fmt.Println("parts=", parts0)25  fmt.Println("value=", value0)26  fmt.Println("hasError=", hasErrortrue)27  fmt.Println("status=", status"handled")28}
    outputparts= 0
    value= 0
    hasError= true
    status= handled
  1. parts ← 5

    15func main() {16  var parts→ 5 = 517  value, err := divide(10, parts5)18  hasError := err != nil
  2. func divide(total int, parts int) (int, error)

    8func divide(total10 int, parts5 int) (int, error) {9  if parts == 0 {10    return 0, errors.New("parts must not be zero")11  }12  return total10 / parts5, nil13}
  3. value ← 2, err ← <nil>, hasError ← false, status ← "pass"

    16  var parts = 517  value→ 2, err→ <nil> := divide(10, parts5)18  hasError→ false := err<nil> != nil19  status→ "pass" := "pass"20  if hasError {21    status = "handled"22  }2324  fmt.Println("parts=", parts5)25  fmt.Println("value=", value2)26  fmt.Println("hasError=", hasErrorfalse)27  fmt.Println("status=", status"pass")28}
    outputparts= 5
    value= 2
    hasError= false
    status= pass

Check the Bad Input

  1. Call divide with a selected parts value.
  2. parts == 0 creates an error.
  3. err != nil records whether the error path happened.
  4. The status changes only when the error was handled. | parts | Expected error check | | --- | --- | | 2 | err == nil | | 0 | err != nil |

Exercise: error_checks.go

Call divide with zero parts, check err != nil, and print handled instead of using a bad value