https://github.com/jeetkd/rswAES256

 

GitHub - jeetkd/rswAES256: demo-ransomeware for studying

demo-ransomeware for studying. Contribute to jeetkd/rswAES256 development by creating an account on GitHub.

github.com

 

프로젝트 동작과정

1. 피해자PC 에서 악성코드 프로그램을 실행하면 C2 서버로 공개키를 요청합니다.(GET 요청)

2. 프로그램은 공개키를 받고 파일들을 암호화 한 후 AES에 사용된 키를 공개키를 사용하여 암호화 시킵니다.

3. 암호화 시킨 키를 C2 서버로 보냅니다.(POST 요청)

4. 피해자가 해커에게 돈을 지불하면, 해커가 C2 서버에 있는 개인키를 사용하여 키를 복호화 전송해줍니다.

 

- 프로젝트 실습 준비 -

go build -o encryption.exe .\cmd\main.go

go build -o decryption.exe .\display\main.go

go run ./server/main.go

New-Item -Path "config.toml" -ItemType File

// config.toml 파일을 열고 작성.
[network]
URI = "http://localhost:8080/api/publickey"
port = ":8080"

[extensions]
targets = [".txt", ".pdf", ".hwp", ".png", ".xlsx"]
newExt = "jkd"

 

1. go build 명령어로 파일을 암호화 하기 위한 .exe 파일을 만들어줍니다.

2. go build 명령어로 파일을 복호화 하기 위한 .exe 파일을 만들어줍니다.

3. C2 서버를 실행 시켜줍니다.

4. config.toml 설정파일을 만들어줍니다.(파워쉘 기준 명령어)

5. config.toml 파일을 열고 아래 설정 값들을 작성해줍니다.

 

- 프로젝트 실습 -

실습

 

'프로그래밍 > Go(golang) 프로젝트' 카테고리의 다른 글

Go(golang) rest api 프로젝트  (0) 2024.07.30

1. Mock servers

1. Mock servers 클릭 -> +로 추가 -> {{url}}/user/1 형식으로 request url 추가 -> Next 클릭.

 

2. Mock servers

2. Mock server Name 입력 -> Save the mock server URL as an new environment variable 체크 표시 -> Create Mock Server 클릭.

 

3. Created Mock server

3. Send a request to the following mock server URL, followed by the request path 복사 -> No environment 클릭하여 shop 으로 환경 변경.

 

JSON 응답 설정.

4.  Collection 클릭 -> shop에서 GET user/1 아래에 Default 클릭 -> JSON으로 { "name" : "jkd"} 응답 설정 -> Save.

 

GET 요청 테스트

5. GET user/1 클릭 -> Send 클릭. -> 아래 Body에 응답메시지가 json 형태로 온것을 볼수 있음.

 

크롬에서 테스트

 

6. 3.에서 복사한 경로뒤에 /user/1을 추가하여 url창에 넣어서 테스트.

https://github.com/jeetkd/plabfootball

 

GitHub - jeetkd/plabfootball: 플랩풋볼 women이 신청한 구장 가져오는 프로젝트

플랩풋볼 women이 신청한 구장 가져오는 프로젝트. Contribute to jeetkd/plabfootball development by creating an account on GitHub.

github.com

 


프로젝트 설명.

 

1. json으로 { "sex" : 0, "region" : 2, "sch" : "2024-07-30" }, 가져올 도시 정보와 날짜, 성별을 post 요청으로 서버(http://localhost:8080/mongo/add)에 요청.

- sex(성별) : (여=0,남=1)

- region(구장 도시정보) : (2 = 경기도)

- sch(구장 날짜) : ("2024-07-30")

 

2. 서버에서 json 데이터를 재가공하여 mongodb에 저장.

 

3. mongodb에 저장된 document.

{

   _id : ObjectId('66a7eksl82ls83e')
    url : https://www.plabfootball.com/api/v2/integrated-matches/?page_size=700&ordering=schedule&sch=2024-07-30&sex=0&hide_soldout=region=2
    sch : "2024-07-30"
    sex : 0
    region : 2
    updatedAt : 2024-07-29T18:56:32.734+00:00
    createdAt : 2024-07-29T18:56:32.734+00:00
    expireAt : 2024-08-05T18:56:32.734+00:00

}

 

4. json으로 { "region" : 2, "sch" : "2024-07-30" }, 특정성별에 따른 구장 정보를 가져올 도시 정보와 날짜를 post 요청으로 서버(http://localhost:8080/mongo/plaber-girl)에 요청.

 

5. postman에서 보낸 json 데이터로 mongodb에 document 요청.

 

6. 요청한 document가 존재하면 document를 서버에 반환합니다.

 

7. 반환한 document 정보를 통해서 플랩풋볼 사이트에서 원하는 정보만 가져옵니다.

 


프로젝트 실습

 

#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 명령어로 테스트 범위와 통과 확인.

 

html 파일로 테스트 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/

#0. 테이블 드리븐 테스트에서 사용자 입력에 대한 테스트

사용자가 어떤 값을 입력한다고 가정하여 그 값과 예상되는 값과 일치하는지 비교합니다. 

 

#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"
	"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)
		}
	}
}

2. main_test.go 파일 (func Test_checkNumbers)

 1. tests에 테이블 테스트를 위한 구조체 슬라이스 저장.

 2. name(값 이름),  input(사용자가 입력을 했다고 가정), expected(사용자 입력(input)에 따른 예상되는 메세지)

 3. 구조체 슬라이스로 만든 테이블 테스트 슬라이스를 반복문으로 돌면서 확인

 4. input := strings.NewReader(e.input) : e.input에서 문자열을 가져와서 새로운 Reader를 만들어줌.

 5. reader := bufio.NewScanner(input) : input에서 값을 가져와서 새로운 Scanner를 만들어줌.

 6. res, _ := checkNumber(reader) : checkNumbers 함수에 reader를 전달하고 반환 값을 받습니다.

 7. if !strings.EqualFold(res, e.expected) : checkNumber 함수에서 반환한 값과 예상되는 메세지를 비교합니다.

 8. 비교해서 메세지가 똑같으면 성공.

 

#2. 결과

테스트 통과

 

1. go test -v, go test -cover 명령어로 테스트 범위와 통과 확인.

 

html 파일로 테스트 cover 확인

html 파일로 테스트 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/

#0. 테이블 드리븐 테스트에서 터미널에 출력하는 함수 테스트

os.stdout에 표준출력을 우리의 write pipe로 바꿔주고, 바꿔준 pipe로 문자열을 읽어들여서 비교해서 테스트.

 

#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 (
    "io"
    "os"
    "testing"
)

func Test_isPrime(t *testing.T) {
    primeTests := []struct {
       name     string
       testNum  int
       expected bool
       msg      string
    }{
       // 1. testNum의 이름, 2. 테스트할 값, 3. 예상되는 값(bool), 4. 예상되는 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)
       // 예상되는 값(bool)이 true 이지만 false를 얻은 경우 테스트 실패
       if e.expected && !result {
          t.Errorf("%s: expected true but got false", e.name)
       }
       // 예상되는 값(bool)이 false 이지만 true를 얻은 경우 테스트 실패
       if !e.expected && result {
          t.Errorf("%s: expected false but got true", e.name)
       }

       // 반환된 값(string)과 예상되는 값(string) 메세지가 다른 경우 테스트 실패
       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 writer

    _ = 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))
    }
}

2. main_test.go 파일 (func Test_prompt)

 1. oldOut 변수에 표준출력을 저장시켜 놓음.

 2. os.pipe() 함수를 통해서 읽거나 쓸수 있는 파일 쌍을 반환

 3. os.Stdout = w, 표준출력을 설정한 os.Stdout에 os.Pipe로 반환한 w(파일에 쓸수 있는)를 적용시킴

 4. prompt()를 실행 시켜서 터미널에 출력하던 문자열을 w로 출력함.

 5. w.Close()로 w를 닫아줌.

 6. os.Stdout = oldOut을 통해서 다시 표준출력으로 복구시킴.

 7. out, _ := io.ReadAll(r), 4번을 통해서 실행 시킨 문자열을  out으로 모두 읽어옴

 8. if string(out) != "-> ", prompt 함수에서 출력하는 문자열이 맞는지 확인.

 

#2. 결과

테스트 통과

1. go test -v, go test -cover 명령어로 테스트 범위와 통과 확인.

 

html 파일로 테스트 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/

#0. 테이블 드리븐 테스트(Table Driven Test)

테이블 드리븐 테스트란 함수에 대한 여러 입력 값과 예상 결과를 배열이나 슬라이스와 같은 데이터 구조를 사용하여 입력 값과 예상 결과를 나열하고, 각 입력 값에 대한 예상 결과를 검증하는 테스트 기법.

 

#1. 실습

maim.go와 main_test.go로 테스트 실습.

package main

import "fmt"

func main() {
    n := 2

    _, msg := isPrime(n)
    fmt.Println(msg)
}

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)를 체크한다.
이 main.go로 테이블 드리븐 테스트 방식으로 테스트 파일을 만들어보면.

 

package main

import "testing"

func Test_isPrime(t *testing.T) {
	primeTests := []struct {
		name     string
		testNum  int
		expected bool
		msg      string
	}{
    	// 1. testNum의 이름, 2. 테스트할 값, 3. 예상되는 값(bool), 4. 예상되는 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)
		// 예상되는 값(bool)이 true 이지만 false를 얻은 경우 테스트 실패
		if e.expected && !result {
			t.Errorf("%s: expected true but got false", e.name)
		}
		// 예상되는 값(bool)이 false 이지만 true를 얻은 경우 테스트 실패
		if !e.expected && result {
			t.Errorf("%s: expected false but got true", e.name)
		}

		// 반환된 값(string)과 예상되는 값(string) 메세지가 다른 경우 테스트 실패
		if e.msg != msg {
			t.Errorf("%s: expected %s but got %s", e.name, e.msg, msg)
		}
	}
}

2. main_test.go 파일(func Test_isPrime)

primeTests라는 구조체 슬라이스를 만들어 줍니다. name(값 이름),  testNum(테스트할 값), expected(예상되는 값), msg(예상되는 값(메시지)) 형식으로 값을 넣어 주고, primeTests를 반복문 으로 돌면서 primeTests 구조체 슬라이스 안에 있는 예상되는 값들과 isPrime함수에 testNum(테스트할 값)을 넣고 반환되는 값을 비교하면서 테스트를 실행 합니다.

 

#2. 결과

테스트 통과

1. go test -v, go test -cover 명령어로 테스트 범위와 통과 확인.

 

html 파일로 테스트 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/

#0.  go test 함수, 파일 만들기

 

1. 파일

*_test.go 형식으로 만듭니다.
예시 1 
파일 : main.go
테스트 파일 : main_test.go
 

2.함수

func TestXxx(*testing.T) 형식으로 만듭니다.
예시 1
함수 : func Check()
테스트 함수 : TestCheck(t *testing.T)
예시 2 (함수가 소문자로 시작하는 경우 _ 추가)
함수 : func checkNumbers()
테스트 함수 : Test_checkNumbers(t *testing.T)
 

#1. 테스트 명령어

go test . : 현재 경로에 있는 go 테스트 파일을 실행한다.
go test -v . : 현재 경로에 있는 go 테스트 파일을 실행하는데, -v(verbosed 약자) 옵션으로 추가 정보를 표시한다. (테스트 파일안에 잇는 각 함수에 대한 테스트 결과 표시)
go test -cover . : 현재 경로에 있는 테스트 코드들이 얼마나 test 되었는지 %(백분율)로 보여줌.
go test -coverprofile=coverage.out : coverage 정보를 coverage.out이라는 파일을 만들어 저장시켜줌
go tool cover -html=coverage.out : coverage.out이라는 파일을 html기반으로 크롬에서 보기 쉽게 해줌(크롬으로 열어보면 테스트된 부분을 표시해줌)
go tool cover -html=coverage.out -o cover.html : coverage.out 파일을 html형식으로 만들어줌(크롬으로 열어보면 테스트된 부분을 표시해줌)
 

#2. 테스트 실습

maim.go와 main_test.go로 테스트 실습.
 

package main

import "fmt"

func main() {
   n := 2

   _, msg := isPrime(n)
   fmt.Println(msg)
}

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)를 체크한다.
이 main.go로 테스트 파일을 만들어보면.
 

package main

import "testing"

func Test_isPrime(t *testing.T) {
   /* 0인 경우 테스트 */
   result, msg := isPrime(0)

   // isPrime 함수에 0을 넣고 result에 false를 예상했지만 true를 얻은 경우 테스트 실패
   if result {
      t.Errorf("with %d as test parameter, got true, but expected false", 0)
   }

   // isPrime 함수에 0을 넣고 msg에 "0 is not prime, by definition!"를 예상했지만 틀린 경우 테스트 실패
   if msg != "0 is not prime, by definition!" {
      t.Error("wrong message returned:", msg)
   }
   
   /* 7인 경우 테스트 */
   result, msg = isPrime(7)
   // isPrime 함수에 7을 넣고 result에 true를 예상했지만 false를 얻은 경우 테스트 실패
   if !result {
      t.Errorf("with %d as test parameter, got false, but expected true", 7)
   }
   // isPrime 함수에 7을 넣고 msg에 "7 is a prime number!"를 예상했지만 틀린 경우 테스트 실패
   if msg != "7 is a prime number!" {
      t.Error("wrong message returned:", msg)
   }
   
   /* -1인 경우 테스트 */
   result, msg = isPrime(-1)
   // isPrime 함수에 -1을 넣고 result에 false를 예상했지만 true를 얻은 경우 테스트 실패
   if result {
      t.Errorf("with %d as test parameter, got true, but expected false", -1)
   }
   // isPrime 함수에 -1을 넣고 msg에 "Negative numbers are not prime, by definition!"를 예상했지만 틀린 경우 테스트 실패
   if msg != "Negative numbers are not prime, by definition!" {
      t.Error("wrong message returned:", msg)
   }

   /* 10인 경우 테스트 */
   result, msg = isPrime(10)
   // isPrime 함수에 10을 넣고 result에 false를 예상했지만 true를 얻은 경우 테스트 실패
   if result {
      t.Errorf("with %d as test parameter, got true, but expected false", 10)
   }
   // isPrime 함수에 10을 넣고 msg에 "10 is not a prime number because it is divisible by 2"를 예상했지만 틀린 경우 테스트 실패
   if msg != "10 is not a prime number because it is divisible by 2" {
      t.Error("wrong message returned:", msg)
   }
}

2. main_test.go 파일

isPrime함수에 0, 7, -1, 10을 넣었을때의 경우를 테스트, 즉 모든 예외의 경우를 테스트 함.
그러나 이렇게 하나씩 짜는건 매우 비효율적 이므로 "테이블 테스트" 방식으로 짜는게 더 간단해짐.
 

#3. 결과

테스트 통과

1. go test -v, go test -cover 명령어로 테스트 범위와 통과 확인.
 

html 파일로 테스트 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/

+ Recent posts