将 EasyMock 与线程一起使用
Using EasyMock with threads
这看起来很简单,但我不知道该怎么做。我们有一个状态机,当触发转换时,事件通过 EventManager class 发送。这是在新线程中启动的,因为我们不想在分发事件时阻塞当前线程。
假设我忘记在模拟时期待方法调用。测试现在应该失败了。但这不是因为线程捕获了异常。我也不想传播期望,因为状态机在遇到异常时停止。
public class TestWhosebug {
@Test
public void test(){
EventManager eventManager = EasyMock.createStrictMock(EventManager.class);
EasyMock.replay(eventManager);
MyClass myClass = new MyClass();
myClass.executeStuff(eventManager);
EasyMock.verify(eventManager);
}
private class MyClass{
public void executeStuff(final EventManager eventManager){
new Thread() {
public void run() {
eventManager.sendEvent();
}
}.start();
}
}
interface EventManager{
public void sendEvent();
}
}
eventManager.sendEvent() 抛出 java.lang.AssertionError,但单元测试没有失败。
Exception in thread "Thread-0" java.lang.AssertionError:
Unexpected method call EventManager.sendEvent():
at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:44)
at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:94)
at org.easymock.internal.ClassProxyFactory$MockMethodInterceptor.intercept(ClassProxyFactory.java:97)
at at.ac.TestWhosebug$EventManager$$EnhancerByCGLIB$$cbb0f0e1.sendEvent(<generated>)
at at.ac.TestWhosebug$MyClass.run(TestWhosebug.java:27)
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.58 sec
我该如何测试这种情况?
即使异常确实传播回您的测试,它仍然可能无法正常工作,因为看起来可能存在竞争条件。
例如,在您的测试中,"executeStuff" 会启动线程,但它实际上可能没有机会立即 运行。
如果主线程继续,它可能会在其他线程有机会 运行 之前到达 "verify" 语句。
如果您稍作更改,以便在 class 之外创建线程,测试起来会更容易。
然后您可以使用 UncaughtExceptionHandler 来解决您原来的问题,例如...
public class TestWhosebug {
@Test
public void test(){
TestExceptionHandler exceptionHandler = new TestExceptionHandler();
EventManager eventManager = EasyMock.createStrictMock(EventManager.class);
EasyMock.replay(eventManager);
// Create a MyClass - pass in the eventManager
MyClass myClass = new MyClass(eventManager);
// Create thread
Thread thread = new Thread(myClass);
thread.setUncaughtExceptionHandler(exceptionHandler);
// Run your code
thread.start();
// WAIT FOR THREAD TO FINISH
thread.join();
// Check no exceptions were thrown
exceptionHandler.verifyNoExceptions();
}
private class TestExceptionHandler implements UncaughtExceptionHandler {
private Throwable e;
@Override
public void uncaughtException(Thread t, Throwable e) {
this.e = e;
}
public void verifyNoExceptions() {
if(e != null) {
throw new AssertionError("BOOM! Exception caught", e);
}
}
}
private class MyClass implements Runnable {
private EventManager eventManager;
public MyClass(EventManager eventManager) {
this.eventManager = eventManager;
}
public void run(){
eventManager.sendEvent();
}
}
interface EventManager{
public void sendEvent();
}
}
createStrictMock
的作用是创建一个严格的 Class 模拟,如果在代码中调用的方法在 Testclass 中的特定顺序不符合预期,它将抛出异常。这导致 Unexpected method call
异常(为了成功完成测试用例,不应首先发生异常)。
你需要创建一个漂亮的模拟,即 Easymock.createNiceMock(EventManager.class);
应该解决这个异常
祝你好运!
这看起来很简单,但我不知道该怎么做。我们有一个状态机,当触发转换时,事件通过 EventManager class 发送。这是在新线程中启动的,因为我们不想在分发事件时阻塞当前线程。
假设我忘记在模拟时期待方法调用。测试现在应该失败了。但这不是因为线程捕获了异常。我也不想传播期望,因为状态机在遇到异常时停止。
public class TestWhosebug {
@Test
public void test(){
EventManager eventManager = EasyMock.createStrictMock(EventManager.class);
EasyMock.replay(eventManager);
MyClass myClass = new MyClass();
myClass.executeStuff(eventManager);
EasyMock.verify(eventManager);
}
private class MyClass{
public void executeStuff(final EventManager eventManager){
new Thread() {
public void run() {
eventManager.sendEvent();
}
}.start();
}
}
interface EventManager{
public void sendEvent();
}
}
eventManager.sendEvent() 抛出 java.lang.AssertionError,但单元测试没有失败。
Exception in thread "Thread-0" java.lang.AssertionError:
Unexpected method call EventManager.sendEvent():
at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:44)
at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:94)
at org.easymock.internal.ClassProxyFactory$MockMethodInterceptor.intercept(ClassProxyFactory.java:97)
at at.ac.TestWhosebug$EventManager$$EnhancerByCGLIB$$cbb0f0e1.sendEvent(<generated>)
at at.ac.TestWhosebug$MyClass.run(TestWhosebug.java:27)
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.58 sec
我该如何测试这种情况?
即使异常确实传播回您的测试,它仍然可能无法正常工作,因为看起来可能存在竞争条件。
例如,在您的测试中,"executeStuff" 会启动线程,但它实际上可能没有机会立即 运行。
如果主线程继续,它可能会在其他线程有机会 运行 之前到达 "verify" 语句。
如果您稍作更改,以便在 class 之外创建线程,测试起来会更容易。
然后您可以使用 UncaughtExceptionHandler 来解决您原来的问题,例如...
public class TestWhosebug {
@Test
public void test(){
TestExceptionHandler exceptionHandler = new TestExceptionHandler();
EventManager eventManager = EasyMock.createStrictMock(EventManager.class);
EasyMock.replay(eventManager);
// Create a MyClass - pass in the eventManager
MyClass myClass = new MyClass(eventManager);
// Create thread
Thread thread = new Thread(myClass);
thread.setUncaughtExceptionHandler(exceptionHandler);
// Run your code
thread.start();
// WAIT FOR THREAD TO FINISH
thread.join();
// Check no exceptions were thrown
exceptionHandler.verifyNoExceptions();
}
private class TestExceptionHandler implements UncaughtExceptionHandler {
private Throwable e;
@Override
public void uncaughtException(Thread t, Throwable e) {
this.e = e;
}
public void verifyNoExceptions() {
if(e != null) {
throw new AssertionError("BOOM! Exception caught", e);
}
}
}
private class MyClass implements Runnable {
private EventManager eventManager;
public MyClass(EventManager eventManager) {
this.eventManager = eventManager;
}
public void run(){
eventManager.sendEvent();
}
}
interface EventManager{
public void sendEvent();
}
}
createStrictMock
的作用是创建一个严格的 Class 模拟,如果在代码中调用的方法在 Testclass 中的特定顺序不符合预期,它将抛出异常。这导致 Unexpected method call
异常(为了成功完成测试用例,不应首先发生异常)。
你需要创建一个漂亮的模拟,即 Easymock.createNiceMock(EventManager.class);
应该解决这个异常
祝你好运!