我有一个在一个(主)线程中工作的java代码。从主线程,我产生一个新的线程,我在其中进行服务器调用。服务器调用完成后,我在新线程中做了一些工作,然后代码加入主线程。
我正在使用eclipse Jobs来进行服务器调用。
我想知道,我如何为此编写JUnit测试用例。
答案 0 :(得分:8)
您可能需要重新构建代码,以便轻松测试。
我可以看到几个不同的测试区域:
构建您的实现,以便您的线程管理代码与Worker的详细信息无关。然后,您可以使用Mock Workers来启用线程管理测试 - 例如,以某种方式失败的Mock Worker允许您测试管理代码中的某些路径。
实现Worker代码,以便它可以独立运行。然后,您可以使用服务器的模拟单独对此进行单元测试。
对于并发测试,Abhijeet Kashnia提供的链接将有所帮助。
答案 1 :(得分:5)
这是为ConcurrentUnit创建的。一般用法是:
有关详细信息,请参阅ConcurrentUnit页面。
答案 2 :(得分:2)
我建议您使用模拟框架,以确认服务器调用确实已经完成。至于线程单元测试:Unit testing multithreaded applications
答案 3 :(得分:2)
Abhijeet Kashnia提供的资源可能有所帮助,但我不确定您要实现的目标。
您可以使用模拟进行单元测试来验证您的代码,这些代码不会测试并发性,但会提供覆盖率。 您可以编写集成测试来验证是否以您期望的方式创建和加入线程。但是,这不能保证不会出现并发问题。大多数并发问题是由时间错误引起的,这些错误是无法预测的,因此无法准确测试。
答案 4 :(得分:1)
我猜你可能已经完成了你的模拟代码,可能需要一个简单的集成测试来确保你的服务器调用工作。
测试线程的一个难点来自于它们的本质 - 它们是并发的。这意味着您需要编写JUnit测试代码,在测试代码结果之前,该代码必须等到线程完成其工作。这不是测试代码的一种非常好的方法,并且可能不可靠,但通常意味着您对代码是否正常工作有所了解。
例如,您的代码可能类似于:
@Test
public void myIntegrationTest() throws Exception {
// Setup your test
// call your threading code
Results result = myServerClient.doThreadedCode();
// Wait for your code to complete
sleep(5);
// Test the results
assertEquals("some value",result.getSomeValue());
}
private void sleep(int seconds) {
try {
TimeUnit.SECONDS.sleep(seconds);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
我真的不喜欢这样做,喜欢嘲笑并同意其他答案。但是,如果你需要测试你的线程,那么这是我发现的一种方法。
答案 5 :(得分:0)
这是我使用thread.start测试asynchrone方法的解决方案:
public class MyClass {
public void doSomthingAsynchrone() {
new Thread(() -> {
doSomthing();
}).start();
}
private void doSomthing() {
}
}
@RunWith(PowerMockRunner.class)
@PrepareForTest(MyClass.class)
public class MyClassTest {
ArgumentCaptor<Runnable> runnables = ArgumentCaptor.forClass(Runnable.class);
@InjectMocks
private MyClass myClass;
@Test
public void shouldDoSomthingAsynchrone() throws Exception {
// create a mock for Thread.class
Thread mock = Mockito.mock(Thread.class);
// mock the 'new Thread', return the mock and capture the given runnable
whenNew(Thread.class).withParameterTypes(Runnable.class)
.withArguments(runnables.capture()).thenReturn(mock);
myClass.doSomthingAsynchrone();
runnables.getValue().run();
/**
* instead of 'runnables.getValue().run();' you can use a real thread.start
*
* MockRepository.remove(Thread.class);
* Thread thread = new Thread(runnables.getValue());
* thread.start();
* thread.join();
**/
verify(myClass, times(1)).doSomthing();
}
}
答案 6 :(得分:0)
当唯一的问题是等待结果时,请使用ExecutorService生成线程。它可以同时接受Runnable和Callable的工作作业。当使用后者时,将为您提供一个Future对象作为回报,该对象可用于等待结果。无论如何,您都应该考虑使用 ExecutorService ,据我了解,您创建了许多线程,这是执行程序服务的完美用例。
class AnyClass {
private ExecutorService threadPool = Executors.newFixedThreadPool(5);
public List<Future<Integer>> anyMethod() {
List<Future> futures = new ArrayList<>();
futures.add(threadPool.submit(() -> {
// Do your job here
return anyStatusCode;
}));
futures.add(threadPool.submit(() -> {
// Do your other job here
return anyStatusCode;
}));
return futures;
}
}
测试类:
class TestAnyClass {
@Test
public void testAnyMethod() {
AnyClass anyObject = new AnyClass();
List<Future<Integer>> futures = anyObject.anyMethod();
CompletableFuture[] completable = futures.toArray(new CompletableFuture[futures.size()]);
// Wait for all
CompletableFuture.allOf(completable).join();
}
}