使用 'this' 关键字调用的 Mockito 存根方法
Mockito stub method invoked using 'this' keyword
我必须测试一些 SLSB 的方法,它调用当前对象的另一个方法(使用 this 关键字),我需要以某种方式存根它。
考虑以下简化代码:
@Local
public interface SomeService{
public int someMethod();
public int anotherMethod();
}
@Stateless()
public class SomeServiceImpl{
@EJB
private SomeDAO sDAO;
public SomeServiceImpl(){}
public SomeServiceImpl(SomeDAO sDAO){
this.sDAO = sDAO;
}
@Override
public int someMethod(){
int dbValue = sDAO.getSomeDBValue(); // 1st stub required here
return dbValue + this.anotherMethod(); // 2nd stub required here
}
@Override
public int anotherMethod(){
return 5;
}
}
为了存根 getSomeDBValue() 方法,我可以使用 @Mock 和 @InjectMocks 注释向这个 class 注入模拟,但我不知道如何正确存根 anotherMethod()。为了存根,我肯定需要在模拟对象上做它,所以我尝试将对当前对象的引用作为参数传递,并在测试中只传递模拟对象。
例如,如果我的方法看起来像这样(不需要存根 DAO 方法)..
@Override
public int someMethod(SomeServiceImpl sS){
return sS.anotherMethod();
}
我使用手动创建的模拟的测试如下所示:
@Test
public void someMethodTest() throws Exception {
SomeServiceImpl sS = mock(SomeServiceImpl.class);
when(sS.someMethod(any(SomeServiceImpl.class))).thenCallRealMethod();
when(sS.anotherMethod()).thenReturn(5);
assertEquals(5, sS.someMethod(sS));
}
方法在模拟对象上调用,对对象本身的引用作为参数传递,另一个方法被存根。它有效,但它似乎是非常丑陋的解决方案,如果需要使用这样的注释注入我的 DAO 的模拟怎么办:
@RunWith(MockitoJUnitRunner.class)
public class SomeClassTest{
@Mock
SomeDAO sDAO;
//@Mock //I can't use those 2 annotations at once
@InjectMocks
SomeServiceImpl sS;
@Test
public void someMethodTest() throws Exception {
//...
}
}
据我所知,@InjectMocks 注释用于指示 class 应在何处注入带有 @Mock 注释的模拟,但对于我丑陋的解决方案,我也需要模拟 SomeServiceImpl。
我的解决方案是否接近正确?我应该如何存根 anotherMethod() 以正确测试 someMethod()?传递 class 的模拟实例是个好主意,我在方法参数中测试了哪个方法?如果是,我应该如何处理创建带注释的模拟?
您不应该在 same class 上测试另一个方法时模拟 one 方法。理论上你可以这样做(使用 Mokito spy
例如)。
从这个意义上说,您在错误的层面上接近了这个:您实际上不应该关心您的测试方法在您的 class 测试中调用了哪些其他方法。你看,你想测试 someMethod()
确实履行了它的合同。如果这需要在您的生产环境中调用 anotherMethod()
...您的单元测试在模拟 anotherMethod()
时有多大价值?!
另一个想法:您将关注点分开,并将 anotherMethod()
部分移动到它自己的 class X 中。然后您的 class 被测试可以包含 X 的实例;然后可以模拟该实例。
我必须测试一些 SLSB 的方法,它调用当前对象的另一个方法(使用 this 关键字),我需要以某种方式存根它。
考虑以下简化代码:
@Local
public interface SomeService{
public int someMethod();
public int anotherMethod();
}
@Stateless()
public class SomeServiceImpl{
@EJB
private SomeDAO sDAO;
public SomeServiceImpl(){}
public SomeServiceImpl(SomeDAO sDAO){
this.sDAO = sDAO;
}
@Override
public int someMethod(){
int dbValue = sDAO.getSomeDBValue(); // 1st stub required here
return dbValue + this.anotherMethod(); // 2nd stub required here
}
@Override
public int anotherMethod(){
return 5;
}
}
为了存根 getSomeDBValue() 方法,我可以使用 @Mock 和 @InjectMocks 注释向这个 class 注入模拟,但我不知道如何正确存根 anotherMethod()。为了存根,我肯定需要在模拟对象上做它,所以我尝试将对当前对象的引用作为参数传递,并在测试中只传递模拟对象。 例如,如果我的方法看起来像这样(不需要存根 DAO 方法)..
@Override
public int someMethod(SomeServiceImpl sS){
return sS.anotherMethod();
}
我使用手动创建的模拟的测试如下所示:
@Test
public void someMethodTest() throws Exception {
SomeServiceImpl sS = mock(SomeServiceImpl.class);
when(sS.someMethod(any(SomeServiceImpl.class))).thenCallRealMethod();
when(sS.anotherMethod()).thenReturn(5);
assertEquals(5, sS.someMethod(sS));
}
方法在模拟对象上调用,对对象本身的引用作为参数传递,另一个方法被存根。它有效,但它似乎是非常丑陋的解决方案,如果需要使用这样的注释注入我的 DAO 的模拟怎么办:
@RunWith(MockitoJUnitRunner.class)
public class SomeClassTest{
@Mock
SomeDAO sDAO;
//@Mock //I can't use those 2 annotations at once
@InjectMocks
SomeServiceImpl sS;
@Test
public void someMethodTest() throws Exception {
//...
}
}
据我所知,@InjectMocks 注释用于指示 class 应在何处注入带有 @Mock 注释的模拟,但对于我丑陋的解决方案,我也需要模拟 SomeServiceImpl。
我的解决方案是否接近正确?我应该如何存根 anotherMethod() 以正确测试 someMethod()?传递 class 的模拟实例是个好主意,我在方法参数中测试了哪个方法?如果是,我应该如何处理创建带注释的模拟?
您不应该在 same class 上测试另一个方法时模拟 one 方法。理论上你可以这样做(使用 Mokito spy 例如)。
从这个意义上说,您在错误的层面上接近了这个:您实际上不应该关心您的测试方法在您的 class 测试中调用了哪些其他方法。你看,你想测试 someMethod()
确实履行了它的合同。如果这需要在您的生产环境中调用 anotherMethod()
...您的单元测试在模拟 anotherMethod()
时有多大价值?!
另一个想法:您将关注点分开,并将 anotherMethod()
部分移动到它自己的 class X 中。然后您的 class 被测试可以包含 X 的实例;然后可以模拟该实例。