의존성 주입 = 클래스에 필요한 인자를 내부에서 생성하지 않고 외부에서 제공.
package notifications
import (
"errors"
"testing"
"github.com/fteem/order-notifications/user"
)
func TestInformOrderShipped(t *testing.T) {
cases := []struct {
user user.User
orderID string
sendingError error
name string
want bool
}{
{
user: user.User{"Peggy", "+12 345 678 999"},
orderID: "12345",
sendingError: nil,
want: true,
name: "Successful send",
},
{
user: user.User{"Peggy", "+12 345 678 999"},
orderID: "12345",
sendingError: errors.New("Sending failed"),
want: false,
name: "Unsuccessful send",
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
**mockSend := func(user.User, string) error {
return tc.sendingError
}//스파이함수**
got := InformOrderShipped(tc.user, tc.orderID, **mockSend**)
if tc.want != got {
t.Errorf("Want '%t', got '%t'", tc.want, got)
}
})
}
}
package notifications
import (
"fmt"
"os/user"
)
func InformOrderShipped(receiver user.User, orderID string, **sendSMS func(user.User, string) error**) bool {
message := fmt.Sprintf("Your order #%s is shipped!", orderID)
//function closure argument
err := sendSMS(receiver, message)
if err != nil {
return false
}
return true
}
함수를 고차함수의 인자로 전달하고, 해당 함수는 외부의 다른 인수에 접근
(function closure arg.)
⇒ 쉽게 mock & test가능,
원래는
package notifications
import (
"fmt"
"github.com/fteem/order-notifications/sms"
"github.com/fteem/order-notifications/user"
)
func InformOrderShipped(receiver user.User, orderID string) bool {
message := fmt.Sprintf("Your order #%s is shipped!", orderID)
err := sms.Send(receiver, message)
if err != nil {
return false
}
return true
}
---
package sms
import (
"time"
"github.com/fteem/order-notifications/user"
)
func Send(receiver user.User, message string) error {
// Simulating API call...
time.Sleep(3 * time.Second)
return nil
}
이와 같이 코드를 작성하고,
아래와 같이 테스트 코드를 썼다. 하지만 이러면 비동기 처리가 들어간 함수 테스팅의 경우엔 테스트 시간이 낭비된다는 문제점이있다.
package notifications
import "testing"
func TestInformOrderShipped(t *testing.T) {
user := User{
Name: "Peggy",
Phone: "+12 345 678 999",
}
orderID := "12345"
got := InformOrderShipped(user, orderID) //에러나면 테스트할 방법없움
want := true
if want != got {
t.Errorf("Want '%t', got '%t'", want, got)
}
}