我有一个类通常在一个线程中运行,该线程永远处理数据,直到另一个线程对它调用stop()。我遇到的问题是单元测试卡在主循环中,因为测试是单线程的,我想保持这种方式。如何在不污染代码的情况下对其进行单元测试?这个类是关键系统的一部分,需要尽可能简单有效,所以我想避免代码中的单元测试黑客
public class MyClass implements Runnable {
boolean running;
public void run() {
//foo is injected from the outside
foo.start();
work();
foo.end();
}
public void work() {
running = true;
while(running) { //main loop
bar.process(); //bar is injected from the outside
}
}
public void stop() {
running = false;
}
}
基本上我在测试中做的是嘲笑 foo 和 bar ,我从单元测试中调用run()
,后来我验证了 bar 模拟是否实际调用了process
。我还验证了在 foo 模拟start()
和end()
被调用。问题是因为我真的想保持测试单线程,测试线程永远停留在while(running)
循环中。
我尝试过但不喜欢的一些事情
stop()
。 Mockito不喜欢我调用另一个类'方法并抛出异常的事实是否有任何其他建议或常用模式来测试Runnables,或者更好的方法来编写我的代码以便更容易测试?
答案 0 :(得分:5)
我建议进行一项更改,这将使您的代码更多地通过书籍和允许在单个帖子中突破:
while (!Thread.currentThread().isInterrupted() && running) {
bar.process();
}
您可以在运行此代码之前调用Thread.currentThread().interrupt()
;线程的interrupted
标志将被设置,方法isInterrupted()
将返回true。
这更像是一本书,因为它使你的主循环参与了Java的中断机制。
答案 1 :(得分:1)
为仅包含方法bar
的{{1}}类创建一个接口。你的process
似乎足够通用,这样就行了。然后,不是模拟MyClass
,而是创建自己的实现虚拟(或模拟,无论你喜欢称之为什么)。然后,这将调用stop方法,并且只调用一次bar
方法。您可以使用process
方法检查是否使用断言调用了BarMock.process
。另外,我建议您isCalled
使用isRunning
方法,以便检查是否已停止。
MyClass
我认为这种方法比William F. Jameson提出的方法有三个优点,但也有缺点:
优点:
public interface Processable {
public void process();
}
public class BarMock implements Processable {
private MyClass clazz;
private boolean called;
public BarMock(MyClass clazz) {
this.clazz = clazz;
called = false;
}
@Override
public void process() {
// you can assertTrue(clazz.isRunning()) here, if required
called = true;
clazz.stop();
}
public boolean isCalled() {
return called;
}
}
public class MyClass implements Runnable {
boolean running;
public void run() {
// foo is injected from the outside
foo.start();
work();
foo.end();
}
public void work() {
running = true;
while (running) { // main loop
bar.process(); // bar is injected from the outside
}
}
public void stop() {
running = false;
}
public boolean isRunning() {
return running;
}
}
方法process
方法是否真的停止缺点:
尽管如此,我仍然更喜欢介绍界面,因为它不会过多地污染你的代码,因此付出的代价很小。