我正在编写遗留代码测试,在重构之前,这意味着我不应该更改代码 ... 我正在使用Spring和Hazelcast,我的班级是一个Hazelcast Listener(如果你不知道Hazelcast它没关系,只要知道我不能改变方法的公司)。
@Component
public class MyClass implements EntryAddedListener<String, MyEntry> {
@Autowired
@Qualifier( "asyncExecutor" )
private Executor executor;
@Autowired
private ClassToBeCalled classToBeCalled;
@Override
public void entryAdded( final EntryEvent<String, MyEntry> event ) {
executor.execute( () -> {
...
...
classToBeCalled.methodToBeCalled( event.getValue() );
}
} );
}
}
我想测试一下,调用entryAdded
时,会调用execute
,特别是调用methodToBeCalled
。
我正在尝试不同的方法,但所有这些方法都会遇到一些模拟错误。这是最后一个:
@RunWith(MockitoJUnitRunner.class)
public class MyClass {
@Mock
private Executor asyncExecutor;
@Mock
private ClassToBeCalled classToBeCalled;
@InjectMocks
private MyClass myClass;
@Test
public void entryListenerShouldInvokeTheClassToBeCalled(){
// given
EntryEvent entryEvent = mock(EntryEvent.class);
MyEntry value = mock(MyEntry.class);
when(entryEvent.getValue()).thenReturn(value);
// here some of my tries, all commented because they don't work
// doCallRealMethod().when(asyncExecutor).execute(any(Runnable.class));
// when(executor.execute(any(Runnable.class))).thenCallRealMethod();
// when
myClass.entryAdded(entryEvent);
// then
verify(asyncExecutor, times(1)).execute(any(Runnable.class));
verify(classToBeCalled, times(1)).methodToBeCalled(value);
}
}
基本上我无法验证是否调用了methodToBeCalled
,因为Executor是一个抽象类。我不能间谍,我不能称之为真正的方法。此外,@ Qualifier指的是库中的实现,或多或少是:
@Bean(name = {"AsyncExecutor"})
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
...
...
executor.initialize();
return executor;
}
有什么想法吗?
答案 0 :(得分:1)
你正试图使用太多的嘲笑。你正在嘲笑Executor
,但仍然期望它表现为一个明显不起作用的常规Executor
。
而是使用SyncTaskExecutor
基本上调用executor.execute
进行测试的同步调用,并仅模拟ClassToBeCalled
。
这样的事情,使用ReflectionTestUtils
应该可以解决问题。
public class MyClass {
private Executor executor = new SyncTaskExector();
private ClassToBeCalled classToBeCalled;
private MyClass myClass;
@Before
public setup() {
myClass = new MyClass();
classToBeCalled = mock(ClassToBeCalled.class);
RelfectionTestUtils.setField(myClass, "executor", executor);
RelfectionTestUtils.setField(myClass, "classToBeCalled", classToBeCalled);
}
@Test
public void entryListenerShouldInvokeTheClassToBeCalled(){
// given
EntryEvent entryEvent = mock(EntryEvent.class);
MyEntry value = mock(MyEntry.class);
when(entryEvent.getValue()).thenReturn(value);
// when
myClass.entryAdded(entryEvent);
// then
verify(classToBeCalled, times(1)).methodToBeCalled(value);
}
}
调用methodToBeCalled
的事实也证明execute
方法已被执行。
提示:我建议将其更改为使用基于构造函数的注入而不是字段注入,因为这样可以更轻松地进行测试。
@Component
public class MyClass implements EntryAddedListener<String, MyEntry> {
private final Executor executor;
private final ClassToBeCalled classToBeCalled;
@Autowired
public MyClass(@Qualifier("asyncExecutor") Executor executor, ClassToBeCalled classToBeCalled) {
this.executor=executor;
this.classToBeCalled=classToBeCalled;
}
}
现在您可以移除ReflectionTestUtils
并简单地构建您的对象。
@Before
public void setup() {
classToBeCalled = mock(ClassToBeCalled.class);
myClass = new MyClass(executor, classToBeCalled);
}