#0. 테이블 드리븐 테스트에서 사용자 입력에 대한 고루틴 처리 테스트
채널을 만들어주고 입력(stdin)에 데이터를 써주고(write) 고루틴과 채널을 사용하는 함수에 대한 테스트
#1. 실습
maim.go와 main_test.go로 테스트 실습.
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
// print a welcome message
intro()
// create a channel to indicate when the user wants to quit
doneChan := make(chan bool)
// start a goroutine to read user input and run program
go readUserInput(doneChan)
// block until the doneChan gets a value
<-doneChan
// close the channel
close(doneChan)
// say goodbye
fmt.Println("Goodbye.")
}
func readUserInput(doneChan chan bool) {
scanner := bufio.NewScanner(os.Stdin)
for {
res, done := checkNumbers(scanner)
if done {
doneChan <- true
return
}
fmt.Println(res)
prompt()
}
}
func checkNumbers(scanner *bufio.Scanner) (string, bool) {
// read user input
scanner.Scan()
//check to see if the user wants to quit
if strings.EqualFold(scanner.Text(), "q") {
return "", true
}
// try to convert what the user typed into an int
numToCheck, err := strconv.Atoi(scanner.Text())
if err != nil {
return "Please enter a whole number", false
}
_, msg := isPrime(numToCheck)
return msg, false
}
func intro() {
fmt.Println("Is it Prime?")
fmt.Println("------------")
fmt.Println("Enter a whole number, and we'll tell you if it is a prime number or not. Enter q to quit.")
prompt()
}
func prompt() {
fmt.Print("-> ")
}
func isPrime(n int) (bool, string) {
// 0과 1 처리(0과 1은 소수가 아님)
if n == 0 || n == 1 {
return false, fmt.Sprintf("%d is not prime, by definition!", n)
}
// 0보다 작은 수의 경우
if n < 0 {
return false, "Negative numbers are not prime, by definition!"
}
// 소수인지 아닌지 체크
for i := 2; i <= n/2; i++ {
if n%i == 0 {
// 소수가 아닌 경우
return false, fmt.Sprintf("%d is not a prime number because it is divisible by %d!", n, i)
}
}
//소수인 경우
return true, fmt.Sprintf("%d is a prime number!", n)
}
1. main.go 파일
소수인지 체크하는 프로그램으로써. 소수인 경우, 소수가 아닌 경우, 0과1인 경우, 0보다작은 경우(-1)를 체크한다.
그리고 사용자에게 입력을 받고 문자열을 출력하는 함수(intro(), prompt(), checkNumbers(), readUserInput())들을 추가했다.
package main
import (
"bufio"
"bytes"
"io"
"os"
"strings"
"testing"
)
func Test_isPrime(t *testing.T) {
primeTests := []struct {
name string
testNum int //테스트 할 값
expected bool //예상되는 bool값
msg string //예상되는 메시지
}{
{"prime", 7, true, "7 is a prime number!"},
{"not prime", 8, false, "8 is not a prime number because it is divisible by 2!"},
{"zero", 0, false, "0 is not prime, by definition!"},
{"one", 1, false, "1 is not prime, by definition!"},
{"negative number", -11, false, "Negative numbers are not prime, by definition!"},
}
for _, e := range primeTests {
result, msg := isPrime(e.testNum)
//true가 예상되지만 false를 반환한 경우
if e.expected && !result {
t.Errorf("%s: expected true but got false", e.name)
}
//false가 예상되지만 true를 반환한 경우
if !e.expected && result {
t.Errorf("%s: expected false but got true", e.name)
}
//예상되는 e.msg값과 반환한 msg값이 다른 경우
if e.msg != msg {
t.Errorf("%s: expected %s but got %s", e.name, e.msg, msg)
}
}
}
func Test_prompt(t *testing.T) {
// save a copy of os.Stdout
oldOut := os.Stdout
// create a read and write pipe
r, w, _ := os.Pipe()
// set os.Stdout to our write pipe
os.Stdout = w
prompt()
// close our write
_ = w.Close()
// reset os.Stdout to what it was before
os.Stdout = oldOut
// read the output of our prompt() func from our read pipe
out, _ := io.ReadAll(r)
// perform our test
if string(out) != "-> " {
t.Errorf("incorrect prompt: expected -> but got %s", string(out))
}
}
func Test_intro(t *testing.T) {
// save a copy of os.Stdout
oldOut := os.Stdout
// create a read and write pipe
r, w, _ := os.Pipe()
// set os.Stdout to our write pipe
os.Stdout = w
intro()
// close our write
_ = w.Close()
// reset os.Stdout to what it was before
os.Stdout = oldOut
// read the output of our prompt() func from our read pipe
out, _ := io.ReadAll(r)
if !strings.Contains(string(out), "Enter a whole number") {
t.Errorf("intro text not correct; got %s", string(out))
}
}
func Test_checkNumbers(t *testing.T) {
tests := []struct {
name string
input string
expected string
}{
{name: "empty", input: "", expected: "Please enter a whole number!"},
{name: "zero", input: "0", expected: "0 is not prime, by definition!"},
{name: "one", input: "1", expected: "1 is not prime, by definition!"},
{name: "two", input: "2", expected: "2 is a prime number!"},
{name: "three", input: "3", expected: "3 is a prime number!"},
{name: "negative", input: "-1", expected: "Negative numbers are not prime, by definition!"},
{name: "typed", input: "three", expected: "Please enter a whole number!"},
{name: "decimal", input: "1.1", expected: "Please enter a whole number!"},
{name: "quit", input: "q", expected: ""},
{name: "QUIT", input: "Q", expected: ""},
}
for _, e := range tests {
input := strings.NewReader(e.input)
reader := bufio.NewScanner(input)
res, _ := checkNumbers(reader)
if !strings.EqualFold(res, e.expected) {
t.Errorf("%s: expected %s, but got %s", e.name, e.expected, res)
}
}
}
func Test_readUserInput(t *testing.T) {
// to test this function, we need a channel, and an instance of an io.Reader
doneChan := make(chan bool)
// create a reference to a bytes.Buffer
var stdin bytes.Buffer
stdin.Write([]byte("1\nq\n"))
go readUserInput(&stdin, doneChan)
<-doneChan
close(doneChan)
}
2. main_test.go 파일 (func Test_readUserInput)
1. doneChan := make(chan bool) : readUserInput(고루틴)과 연결하기 위한 채널 생성.
2. var stdin bytes.Buffer : 임의로 입력할 값을 넣기 위한 가변버퍼 생성.
3. stdin.Write([]byte("1\nq\n")) : 가변버퍼에 1\n(엔터), q\n(엔터)를 넣어 줍니다.
4. q\n : if done { doneChan <- true return } 이 부분이 coverd.
5. 1\n : fmt.Println(res), prompt() 이 부분이 covered.
6. go readUserInput(&stdin, doneChan) : 고루틴으로 readUserInput 함수를 실행
7. <-doneChan : 동시에 main에서 채널에 값이 올때 까지 대기
8. close(doneChan) : 채널을 닫아줌
#2. 결과
1. go test -v, go test -cover 명령어로 테스트 범위와 통과 확인.
2. go test . -coverprofile=coverage.out 명령어로 coverage.out 파일을 만들어줌
3. go tool cover -html=coverage.out(윈도우에서는 .out없이) 명령어로 html 파일로 확인. (초록색 부분이 cover(테스트 코드 작성 완료))
출처
https://www.udemy.com/course/introduction-to-testing-in-go-golang/
'프로그래밍 > Go(golang) 테스트 공부' 카테고리의 다른 글
#3. golang 사용자 입력에 대한 테스트 코드(with 유데미) (0) | 2023.11.11 |
---|---|
#2. golang 터미널에 대한 출력을 확인하는 테스트(with 유데미) (0) | 2023.11.06 |
#1. golang 테이블 드리븐 테스트(with 유데미) (0) | 2023.10.30 |
#0. golang 테스트 코드 공부(with 유데미) (0) | 2023.10.28 |