testable-mock icon indicating copy to clipboard operation
testable-mock copied to clipboard

Springboot+SpringMVC的工程,mock了serviceA的接口方法不生效

Open MichaelXcy opened this issue 4 years ago • 7 comments

Springboot+SpringMVC的工程: 1、工程有两个service类:ServiceA,ServiceB, 2、在ServiceATest类添加了静态类Mock并拷贝了ServiceA.A1()的方法签名以及实现到Mock内 3、在ServiceBTest类内的,不管是new 还是@Autowired 注入 ServiceA,ServiceBTest单元测试类的方法调用ServiceA.A1(),都不会走mock方法,而是走的原方法。 4、如果ServiceBTest单元测试类的方法调用ServiceA.A2(),而ServiceA类中的方法A2() 内调用了ServiceA类的A1(),这样是会走A1方法的mock方法。

MichaelXcy avatar Apr 28 '21 15:04 MichaelXcy

难道是说,被测类的方法的mock要生效,必须要由被测类的另一个方法内调用了目标方法,才会走目标方法的mock实现么?就是一定要由被测类另一个方法包装一层才会生效?

MichaelXcy avatar Apr 28 '21 16:04 MichaelXcy

TestableMock中的Mock使用方式和Mockito等工具不太一样,是让每个业务类自己提供自己的Mock实现,放置在相应测试类里名为Mock的内部类,或者独立的XxxMock类里。

举例来说,ServiceA类型的Mock方法可以放在ServiceATest里的Mock内部类里,或者ServiceAMock类里,这两个地方定义的Mock方法也只对ServiceA类型里的代码调用有Mock作用。

因此上述在ServiceATest.Mock类里定义的A1()方法,在测试时会自动替换ServiceA里的A1()调用,但对不论是从ServiceB还是ServiceBTest里调用的A1()方法都不会生效。

linfan avatar Apr 29 '21 07:04 linfan

这个问题确实需要专门解释一下,近期会在文档里补充一个示意图

linfan avatar Apr 29 '21 07:04 linfan

TestableMock中的Mock使用方式和Mockito等工具不太一样,是让每个业务类自己提供自己的Mock实现,放置在相应测试类里名为Mock的内部类,或者独立的XxxMock类里。

举例来说,ServiceA类型的Mock方法可以放在ServiceATest里的Mock内部类里,或者ServiceAMock类里,这两个地方定义的Mock方法也只对ServiceA类型里的代码调用有Mock作用。

因此上述在ServiceATest.Mock类里定义的A1()方法,在测试时会自动替换ServiceA里的A1()调用,但对不论是从ServiceB还是ServiceBTest里调用的A1()方法都不会生效。

感谢解答,很喜欢你们的极简风格,实现指哪打哪。但是还是不理解,为啥要有必须当前类内部调用目标方法才能mock生效的这个限制呢?

这样使用者如果要对ServiceA.A1()进行mock,还必须要修改ServiceA类的源代码,添加一个内部方法(只是为了测试用)ServiceA.inner(),在内部方法ServiceA.inner()里面调用目标方法A1才能使ServiceATest.mock里面的A1有效,这个场景可能有时候不够友好吧。为了要单元测试添加无用的代码嵌套

MichaelXcy avatar Apr 29 '21 15:04 MichaelXcy

实际不应该出现为了Mock加inner()方法的这种情况的哈。

使用Mock的目的是因为在被测类(业务类)里有某些调用会影响单元测试正在运行,但为了测试改业务代码不合适,所以要用额外机制来Mock掉。测试类里的调用是不需要被Mock的,比如ServiceBTest单元测试类的方法不想调用真实的ServiceA.A1(),那么直接改测试代码就好了,而不是要到被测类去加inner()方法。这样解释不知说清了没有~

对任何Mock工具来说,Mock的目标都只应该是被测类里的调用。

linfan avatar Apr 30 '21 03:04 linfan

实际不应该出现为了Mock加inner()方法的这种情况的哈。

使用Mock的目的是因为在被测类(业务类)里有某些调用会影响单元测试正在运行,但为了测试改业务代码不合适,所以要用额外机制来Mock掉。测试类里的调用是不需要被Mock的,比如ServiceBTest单元测试类的方法不想调用真实的ServiceA.A1(),那么直接改测试代码就好了,而不是要到被测类去加inner()方法。这样解释不知说清了没有~

对任何Mock工具来说,Mock的目标都只应该是被测类里的调用。

嗯嗯,感谢您的耐心解答,我明白了,多谢,希望能后面加上基于springboot的demo

MichaelXcy avatar May 04 '21 03:05 MichaelXcy

也就是Mock容器中mock的各种方法其实是mock的被Mock类中的对外调用。 对应到你的例子: 应该是在 ServiceBMock 中mock ServiceA 的方法 A1() ,这样应该就能发生实际的替换

JiaRG avatar Sep 24 '21 02:09 JiaRG