我正在思考如何使用mockito来编写测试用例。
例如,在我的主线程中,我的部分逻辑是创建一个执行3件事情的线程。请参阅下面我的注释代码。
现在,根据主程序输入的数量,可以多次生成RequestThread。
public class MainThreads {
public static void main(String[] args) {
RequestThread rt = new RequestThread("sample");
rt.start();
//RequestThread another = new RequestThread("sample-2");
//another.start();
//RequestThread newThread = new RequestThread("sample-3");
//newThread.start();
}
public static class RequestThread implements Runnable{
private final String request;
public RequestThread(String request) {
this.request = request;
}
@Override
public void run() {
//1. Instantiate a service passing the required request parameter
MyDataWebService service = new MyDataWebService(request);
//2. Get the returned data
List<String> dataList = service.requestData();
//3. Write to file
Path file = Paths.get("/someDir/" + request);
Files.write(file, dataList, Charset.forName("UTF-8"));
}
}
}我的问题是,我不知道如何正确地为线程类编写JUnit/Mockito测试。总的来说,我在Mockito和JUnit上没有那么好的诗句,所以我正在寻找一种方法来测试线程应用程序。
有人能指点我怎么才能对这种东西进行单元测试吗?
发布于 2018-07-25 07:50:33
您需要对代码进行一些更改,以使其更易于测试。特别是:
下面是对类的重写,以便您可以模拟MyDataWebService并测试RequestThread。基于这个示例,您将能够更容易地为MainThreads类编写完整的测试。
public class MainThreads {
public static void main(String[] args) {
RequestThread rt = new RequestThread("sample");
rt.start();
//RequestThread another = new RequestThread("sample-2");
//another.start();
//RequestThread newThread = new RequestThread("sample-3");
//newThread.start();
}
public static class RequestThread extends Thread {
private final String request;
// One important thing to note here, "service" has to be non-final. Else mockito won't be able to inject the mock.
private MyDataWebServiceInterface service;
public RequestThread(String request) {
this.request = request;
//1. Instantiate a service passing the required request parameter
// => do it in constructor, or passed as parameter, but NOT in the function to test
service = new MyDataWebService(request);
}
@Override
public void run() {
//2. Get the returned data
List<String> dataList = service.requestData();
//3. Write to file
Path file = Paths.get("someDir/" + request);
try {
Files.write(file, dataList, Charset.forName("UTF-8"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}MyDataWebService的接口与实现
interface MyDataWebServiceInterface {
List<String> requestData();
}
class MyDataWebService implements MyDataWebServiceInterface {
public MyDataWebService(String request) {
}
@Override
public List<String> requestData() {
return Arrays.asList("foo", "bar");
}
}以及使用mockito进行的测试。注意,检查现有文件和线程休眠可能不是这里最优雅的事情。如果您能够在RequestThread中添加一些标记来指示数据已经写入,那么这肯定会使测试更好、更安全(文件系统i/o有时很难测试)。
@RunWith(MockitoJUnitRunner.class)
public class RequestThreadTest {
private static final Path FILE = Paths.get("someDir", "sample");
@Mock
MyDataWebServiceInterface service;
@InjectMocks
MainThreads.RequestThread reqThread = new MainThreads.RequestThread("sample");
@Before
public void setup() throws IOException, InterruptedException {
if (Files.exists(FILE)) {
Files.delete(FILE);
while (Files.exists(FILE)) {
Thread.sleep(50);
}
}
}
@Test
public void shouldWriteFile() throws InterruptedException {
Mockito.when(service.requestData()).thenReturn(Arrays.asList("one", "two"));
reqThread.start();
while (!Files.exists(FILE)) {
Thread.sleep(50);
}
// HERE run assertions about file content
}
}现在,测试异步代码通常比同步代码更复杂,因为您经常会遇到不确定性行为、定时问题等。您可能希望在测试中设置一个超时,但请记住:持续集成工具(jenkins,travis等)。运行速度往往比你的机器慢,这是一个常见的问题,所以不要设置太紧。据我所知,对于非确定性问题,没有“一刀切”的解决办法。
马丁·福勒( Martin )在测试中有一篇关于不确定性的优秀文章:https://martinfowler.com/articles/nonDeterminism.html
发布于 2018-07-25 06:31:57
一个与众不同的答案是:2018年,你不再使用“原始”线程了。
到目前为止,Java提供了更好的抽象,例如ExecutorService。您猜怎么着:当您将代码提交任务提交到这样的服务中时,您可能可以使用同螺纹执行器服务对其进行测试。
意义:通过使用这样的抽象并将您的交付分解成特定的服务,您可能(几乎)能够(几乎)完全测试这些小单元,以及任务是如何进入您的系统和如何工作的。
换句话说:您单元测试您的“任务”,然后您“单元”测试任务的集成时,他们进入这样一个执行者。然后,您只需要进行一些实际的函数/集成测试,以检查“真正的并行”解决方案是否符合预期。
其他事情很快就会变得复杂。在普通单元测试中使用真正的线程会导致不一致的行为,或者增加运行时(比如等待线程异步执行的测试)。
如您的示例所示:您的测试只是停留在那里,并定期检查预期的文件是否带有预期的内容。导致:它应该等待多久才能失败?等待时间不够意味着您的测试偶尔会失败,因为代码有时只需要更长的时间。如果等待时间太长,这就意味着运行测试所需的总时间。您不想以数百个单元测试结束--有些测试需要10到20秒,因为“等待其他线程”。
https://stackoverflow.com/questions/51510823
复制相似问题