Go语言 如何覆盖表驱动测试中的模拟调用期望

lndjwyie  于 2023-04-09  发布在  Go
关注(0)|答案(1)|浏览(135)

在处理一个表驱动测试时,我使用了一些由mockery生成的mock,并设置了一些依赖于每个测试用例的数据集中提供的数据的方法调用期望。我面临的问题是,mocked调用总是返回第一个测试用例中期望的结果集,而不是为正在执行的测试用例定义的结果集。

func (s *MyTestSuite) TestMySampleTest() {
    testCases := []struct {
        Name     string
        Requests []*service.CreateCredentialRequest
    }{
        {
            Name:     "first case",
            mockedResult: 1,
            expected: 1,
        },
        {
            Name:     "second case",
            mockedResult: 2,
            expected: 2,
        },
    }

    for _, tc := range testCases {
        s.Run(tc.Name, func() {
            s.someMock.On("SomeMethodCall", mock.Anything).Return(tc.mockedResult)

            result := s.SUT.SomeMethodThatCallsTheMockedObe()

            s.Equal(expected, result)
        })
    }
}

当我运行这个测试时,第二个用例失败了,因为结果是1,而不是预期的2,我可以看到问题是模拟方法返回1(为第一个测试用例设置的值),而不是2(为当前测试用例设置的值)。
有办法解决吗?

yhxst69z

yhxst69z1#

这可能不是最优雅的解决方案,我想知道是否有其他方法可以做到这一点,但就目前而言,我发现了这个解决方案,它包括为表驱动测试运行的每个子测试生成一个新的mock,所以在每个子测试中,我们使用一个新的mock示例,它没有任何来自前一个子测试的期望值。我使用testify.Suite来组织和处理我的测试,这样做就像在每个子测试中手动调用s.SetupTest()方法一样简单:

// SetupTest is executed before every test is run, I instantiate the SUT and 
// its dependencies here.
func (s *MyTestSuite) SetupTest() {
    // Instantiate the mock
    s.someMock = mocks.NewSomeMock(s.T())
    // Instantiate the SUT, injecting the mock through the constructor function
    s.SUT = NewSUT(s.someMock)
}

func (s *MyTestSuite) TestMySampleTest() {
    testCases := []struct {
        Name     string
        Requests []*service.CreateCredentialRequest
    }{
        // test cases here 
    }

    for _, tc := range testCases {
        s.Run(tc.Name, func() {
            // Manually calling s.SetupTest() to generate new instances of the mocks in every subtest.
            // If we don't do this, the mock will always return the first expectation set (the one set for the first test case).
            s.SetupTest()

            // Here comes the logic of the text as we had it before
            s.someMock.On("SomeMethodCall", mock.Anything).Return(tc.mockedResult)

            result := s.SUT.SomeMethodThatCallsTheMockedObe()

            s.Equal(expected, result)
        })
    }
}

相关问题