英文:
How to test Go Mock Repository inside loop on usecase
问题
我有一个使用testify进行存储库模拟数据库测试的问题。
我想要测试一个服务/用例,它为每个迭代创建一个记录数据库。以下是代码:
这段代码包含数据库的模拟
mockrepository.go
package service
import(
"errors"
"github.com/stretchr/testify/mock"
)
type TestRepositoryMock struct {
Mock mock.Mock
}
func (repository *TestRepositoryMock) CreateTodo(todo *Todo) error {
arguments := repository.Mock.Called(todo)
if arguments.Get(0) == nil {
return errors.New("Error")
} else {
return nil
}
}
func (repository *TestRepositoryMock) CreateTodoDetail(todo *TodoDetail) error {
arguments := repository.Mock.Called(todo)
if arguments.Get(0) == nil {
return errors.New("Error")
} else if arguments.Get(1) == nil {
return errors.New("Error")
} else {
return nil
}
}
这个用例的逻辑是为每个项目数量(NumberOfItems
变量)保存TodoDetail
usecase.go
package service
import(
"strconv"
)
type UseCase interface {
SaveTodo(numberOfItems int) (string, error)
}
func NewUseCase(repo Repository) UseCase {
return &useCase{repo: repo}
}
type useCase struct {
repo Repository
}
func (uc *useCase) SaveTodo(numberOfItems int) (string, error){
todo := Todo{
Title: "this is title",
}
uc.repo.CreateTodo(&todo)
for i := 0; i < numberOfItems; i++ {
todoDetail := TodoDetail{
ID: todo.ID,
Item: "item "+ strconv.Itoa(i),
}
uc.repo.CreateTodoDetail(&todoDetail)
}
return "success", nil
}
package service
import(
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
var repository = &TestRepositoryMock{Mock: mock.Mock{}}
var testService = useCase{repo: repository}
func TestService_SaveTodoSuccess(t *testing.T) {
todo := Todo{
Title: "this is title",
}
todoDetail := TodoDetail{
ID: todo.ID,
Item: "item 1",
}
repository.Mock.On("CreateTodo", &todo).Return(nil)
repository.Mock.On("CreateTodoDetail", &todoDetail).Return(nil).Once()
result, err := testService.SaveTodo(3)
assert.Nil(t, err)
assert.NotNil(t, result)
}
如何测试for循环中的多次调用CreateTodoDetail
?
英文:
I have a problem with testing with Repository Mock Database using testify.
I want to test a service/use case that creates a record database for each iteration. Here is the code:
This code contain mock of the database
mockrepository.go
package service
import(
"errors"
"github.com/stretchr/testify/mock"
)
type TestRepositoryMock struct {
Mock mock.Mock
}
func (repository *TestRepositoryMock) CreateTodo(todo *Todo) error {
arguments := repository.Mock.Called(todo)
if arguments.Get(0) == nil {
return errors.New("Error")
} else {
return nil
}
}
func (repository *TestRepositoryMock) CreateTodoDetail(todo *TodoDetail) error {
arguments := repository.Mock.Called(todo)
if arguments.Get(0) == nil {
return errors.New("Error")
} else if arguments.Get(1) == nil {
return errors.New("Error")
} else {
return nil
}
}
the logic inside this use case is to save TodoDetail for each number of items (NumberOfItems variable)
usecase.go
package service
import(
"strconv"
)
type UseCase interface {
SaveTodo(numberOfItems int) (string, error)
}
func NewUseCase(repo Repository) UseCase {
return &useCase{repo: repo}
}
type useCase struct {
repo Repository
}
func (uc *useCase) SaveTodo(numberOfItems int) (string, error){
todo := Todo{
Title: "this is title",
}
uc.repo.CreateTodo(&todo)
for i := 0; i < numberOfItems; i++ {
todoDetail := TodoDetail{
ID: todo.ID,
Item: "item "+ strconv.Itoa(i),
}
uc.repo.CreateTodoDetail(&todoDetail)
}
return "success", nil
}
package service
import(
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
var repository = &TestRepositoryMock{Mock: mock.Mock{}}
var testService = useCase{repo: repository}
func TestService_SaveTodoSuccess(t *testing.T) {
todo := Todo{
Title: "this is title",
}
todoDetail := TodoDetail{
ID: todo.ID,
Item: "item 1",
}
repository.Mock.On("CreateTodo", &todo).Return(nil)
repository.Mock.On("CreateTodoDetail", &todoDetail).Return(nil).Once()
result, err := testService.SaveTodo(3)
assert.Nil(t, err)
assert.NotNil(t, result)
}
How to test the multiple call for CreateTodoDetail
inside for loop?
答案1
得分: 0
为了测试循环使用案例,我们应该提供一些模拟数据,与循环迭代次数相同。
例如,如果使用案例有一个循环迭代3次的循环,每次调用存储库三次,那么我们必须提供3个数据模拟。
代码应该像这样:
func TestService_SaveTodoSuccess(t *testing.T) {
// 模拟实体 Todo
todo := Todo{
Title: "this is title",
}
// 模拟实体 TodoDetail
todoDetail1 := TodoDetail{
ID: todo.ID,
Item: "item 0",
}
todoDetail2 := TodoDetail{
ID: todo.ID,
Item: "item 1",
}
todoDetail3 := TodoDetail{
ID: todo.ID,
Item: "item 2",
}
repository.Mock.On("CreateTodo", &todo).Return(todo)
// 调用 3 次 "CreateTodoDetail" 存储库
repository.Mock.On("CreateTodoDetail", &todoDetail1).Return(todoDetail1)
repository.Mock.On("CreateTodoDetail", &todoDetail2).Return(todoDetail2)
repository.Mock.On("CreateTodoDetail", &todoDetail3).Return(todoDetail3)
result, err := testService.SaveTodo(3)
assert.Nil(t, err)
assert.NotNil(t, result)
}
这个场景构建了3个不同的 todoDetail 数据,以模拟3次迭代调用 CreateTodoDetail
存储库。
英文:
-SOLVED-
For testing on the loop use case, we should provide numbers of mock data. same as loop iteration.
Example. If use case has 3 iteration loop that calls the repository three times then we must provide 3 data mock.
the code should be like this:
func TestService_SaveTodoSuccess(t *testing.T) {
// Mock Entity Todo
todo := Todo{
Title: "this is title",
}
// Mock Entity TodoDetail
todoDetail1 := TodoDetail{
ID: todo.ID,
Item: "item 0",
}
todoDetail2 := TodoDetail{
ID: todo.ID,
Item: "item 1",
}
todoDetail3 := TodoDetail{
ID: todo.ID,
Item: "item 2",
}
repository.Mock.On("CreateTodo", &todo).Return(todo)
// calls 3 times "CreateTodoDetail" Repository
repository.Mock.On("CreateTodoDetail", &todoDetail1).Return(todoDetail1)
repository.Mock.On("CreateTodoDetail", &todoDetail2).Return(todoDetail2)
repository.Mock.On("CreateTodoDetail", &todoDetail3).Return(todoDetail3)
result, err := testService.SaveTodo(3)
assert.Nil(t, err)
assert.NotNil(t, result)
}
The scenario builds 3 different data on todoDetail to mock 3 times iterations for CreateTodoDetail
repository
答案2
得分: 0
为了在一系列模拟响应中运行相同的测试,Mock提供了.Once()
方法,可以重复使用单个模拟,并返回所需的每个结果。
// 循环遍历的数组
todoDetailArray := []TodoDetail{todoDetail1, todoDetail2}
// 针对每个测试场景循环遍历模拟
for eachTodoDetail := range todoDetailArray {
repository.Mock.On("CreateTodoDetail", eachTodoDetail).Return(eachTodoDetail).Once()
...
}
英文:
To run the same test over a range of mocked responses, Mock has a .Once()
method that enables repeating a single mock with each result needed.
// array to loop through
todoDetailArray := []TodoDetail{todoDetail1, todoDetail2}
// loop through mocks for each test scenario
for eachTodoDetail := range todoDetailArray {
repository.Mock.On("CreateTodoDetail", eachTodoDetail).Return(eachTodoDetail).Once()
...
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论