Ad

Testing A Function By Passing Input Multiple Times

- 1 answer

I'm learning Go with tests. I ended up with the below program from the end of chapter 2 in "Head First Go".

It gives the user three attempts to guess a number from 1 to 10:

guess.go

package main

import (
    "fmt"
    "math/rand"
    "time"
    "bufio"
    "os"
    "log"
    "strconv"
    "strings"
)

func generateRandomNumber() int {
    rand.Seed(time.Now().Unix())       // seed value based on time to generate non-deterministic random values
    randomNum := rand.Intn(10) + 1     // range: [0, 10); produces the same value without Seed(), i.e., pseudo-random
    return randomNum
}

func guess() int {
    var success bool = false
    target := generateRandomNumber()

    fmt.Println("Guess a number between 1 and 10")
    guess  := bufio.NewReader(os.Stdin)

    for attempts := 0; attempts < 3; attempts++ {
        fmt.Println("You have", 3-attempts, "guesses left")
        userVal, err := guess.ReadString('\n')
        if err != nil {
            log.Fatal(err)
        }
    
        input := strings.TrimSpace(userVal)
        answer, err := strconv.Atoi(input)
        if err != nil {
            log.Fatal(err)
        }
    
        if answer == target {
            fmt.Println("Congratulations !!")
            return answer
        } else if answer > target {
            fmt.Println("Your guess was HIGHER")
        } else if answer < target {
            fmt.Println("Your guess was LOWER")
        }
    }

    if !success {
        fmt.Printf("Sorry, you've run out of attempts... The correct value is %d\n", target)
        return target   
    }
    return 0
}

func main() {
    guess()
}

guess_test.go

package main

import (
    "testing"
)

func TestRandomNumber(t *testing.T) {
    want := generateRandomNumber()
    
    if 7 != want {
        t.Fail()
        t.Logf("Incorrect guess; The random number was %d", want)
    }
}

How can I test guess() by passing in three different inputs?

I would like to perform a test by comparing the return value of guess() with generateRandomNumber().

Ad

Answer

You can change guess function to get reader from input, by this we able to pass it any reader we want: in main we pass stdin reader and in test we pass mock reader:

guess.go

package main

import (
    "bufio"
    "fmt"
    "log"
    "math/rand"
    "os"
    "strconv"
    "strings"
    "time"
)

func generateRandomNumber() int {
    rand.Seed(time.Now().Unix())   // seed value based on time to generate non-deterministic random values
    randomNum := rand.Intn(10) + 1 // range: [0, 10); produces the same value without Seed(), i.e., pseudo-random
    return randomNum
}

func guess(reader *bufio.Reader) (int, error) {
    target := generateRandomNumber()

    fmt.Println("Guess a number between 1 and 10")

    for attempts := 0; attempts < 3; attempts++ {
        fmt.Println("You have", 3-attempts, "guesses left")
        userVal, err := reader.ReadString('\n')
        if err != nil {
            log.Fatal(err)
        }

        input := strings.TrimSpace(userVal)
        answer, err := strconv.Atoi(input)
        if err != nil {
            log.Fatal(err)
        }

        if answer == target {
            fmt.Println("Congratulations !!")
            return answer, nil
        } else if answer > target {
            fmt.Println("Your guess was HIGHER")
        } else if answer < target {
            fmt.Println("Your guess was LOWER")
        }
    }

    fmt.Printf("Sorry, you've run out of attempts... The correct value is %d\n", target)
    return target, fmt.Errorf("attempts is over")
}

func main() {
    reader := bufio.NewReader(os.Stdin)
    guess(reader)
}

for testing:

guess_test.go

package main

import (
    "bufio"
    "fmt"
    "strings"
    "testing"
)

func TestRandomNumberOk(t *testing.T) {
    want := generateRandomNumber()
    msg := fmt.Sprintf("3\n4\n%d\n", want)
    reader := strings.NewReader(msg)
    r := bufio.NewReader(reader)
    _, err := guess(r)
    if err != nil {
        t.Errorf("guess must successfull")
    }
}

func TestRandomNumberFail(t *testing.T) {
    want := generateRandomNumber()
    msg := fmt.Sprintf("3\n4\n%d\n", want+1)
    reader := strings.NewReader(msg)
    r := bufio.NewReader(reader)
    _, err := guess(r)
    if err == nil {
        t.Errorf("guess must unsuccessfull")
    }
}

I had to change your guess return value, because it's unknown when it's successful or not

Ad
source: stackoverflow.com
Ad