线程中抛出JUnit5检查异常

JUnit5 check exception is thrown in thread

我有这样的服务:

class SomeService{

    private final Executor executor = Executors.newFixedThreadPool(10);

    void handle(SomeEvent event) {
        executor.execute(
                () -> {
                    //... logic omitted
                    if (isBadCase()) {
                        throw new RuntimeException("Something bad happen");
                    } 
                    //... time consuming logic continued
                }
        );
    }

...

//other methods
}

我想测试“badCase”,即 RuntimeException("Something bad happen") 被抛出。 是否可以使用JUnit5实现?

对于“正常”或“notSoBad”的其他情况,我已经实施了变通方法,这只是一个等待周期,以便满足相应情况的某些条件,如下所示:

private void awaitForNormalConditionIsMet(int seconds) {
        for (int step = 1; step <= seconds * 40; step++) {
            if (normalConditionIsMet()) return;
            else {
                try {
                    System.out.println("Waiting for condition - " + (step * 25) + "ms");
                    Thread.sleep(25);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        Assertions.fail();
    }

当我有相应的东西需要检查时,这个解决方法很有效。 但是对于“badCase”没有相应的改变,只是抛出异常。

而且我无法从执行程序中提取异常抛出逻辑。 你能帮忙吗?

您可能想要重构代码,尤其是当您的 Runnable 具有更复杂的逻辑时。

如果您将其作为单独的 单元 进行测试,您可以更好地控制它。而且测试更容易,例如:

public class SomeService {

    private final Executor executor = Executors.newFixedThreadPool(10);

    void handle(SomeEvent event) {
        executor.execute(new MyRunnable(event));
    }

    // This is inner non-static in my example class because isBadCase()
    // could be in service. Of course this isBadCase could be anywhere.
    public class MyRunnable implements Runnable {
        private SomeEvent event; 
        public MyRunnable(SomeEvent event) {
            this.event = event;
        }
        @Override
        public void run() {
            if (isBadCase()) {
                throw new RuntimeException("Something bad happen");
            }                    
        }
    }

    public boolean isBadCase() {
        return false;
    }

}

现在线程没有问题了,因为您可以直接在主线程中捕获异常,同时您正在对代码进行更精细的单元测试:

@ExtendWith(MockitoExtension.class)
class SomeServiceTest {

    // Spy is because you want to mock normal case for isBadCase = false
    // to true so causing the exception to be thrown
    @Spy
    private SomeService someService;
    
    @Test
    void testOk() {
       someService.new MyRunnable(new SomeEvent()).run();
    }

    @Test
    void testBadCase() {
        Mockito.when(someService.isBadCase()).thenReturn(true);
        MyRunnable myRunnable = someService.new MyRunnable(new SomeEvent());
        assertThrows(RuntimeException.class, () -> myRunnable.run());
    }

}