Spring Boot 在@SpringBootTest中测试@Async注解方法

yc0p9oo0  于 2022-11-05  发布在  Spring
关注(0)|答案(2)|浏览(399)

我有一个服务SomeService,其中有一个方法来执行一些逻辑。

@Override
public CompletableFuture<Boolean> process(User user) {
    Objects.requiredNonNull(user, "user must not be null");
    // other logic...
}

那我有个测试。

@RunWith(SpringRunner.class)
@SpringBootTest(classes = { SomeService.class })
public class SomeServiceTest {
    @Autowired private SomeService tested;
    @Test
    public void user_null_expect_NullPointerException() {
        assertThatThrownBy(() -> tested.process(null))
                .isInstanceOf(NullPointerException.class)
                .hasMessage("user must not be null");
    }
}

在我决定使该方法异步之前,它一直工作得很好。

@Async
@Override
public CompletableFuture<Boolean> process(User user) {
    Objects.requiredNonNull(user, "user must not be null");
    // other logic...
}

所以,现在它不工作是因为Spring代理。有人知道我必须如何配置我的测试才能使它再次工作吗?

vcirk6k6

vcirk6k61#

好的,我有一个解决方案。问题不是在异步方法中,问题是在错误的Assert中。我不知道AssertJ能够测试CompletableFuture。
所以我的解决方案是:

@Test
public void user_null_expect_NullPointerException() {
    final CompletableFuture<Boolean> result = getCompletedResult(null);

    assertThat(result)
            .isCompletedExceptionally()
            .hasFailedWithThrowableThat()
            .isInstanceOf(NullPointerException.class)
            .hasMessage("user must not be null");
}

private CompletableFuture<Boolean> getCompletedResult(User user) {
    final CompletableFuture<Boolean> result = tested.process(user);
    await().atMost(10, TimeUnit.SECONDS).until(result::isDone);
    return result;
}

如果你有更好的解决办法,告诉我。

pbpqsu0x

pbpqsu0x2#

当你对你的服务类进行单元测试时,不需要启动一个Spring上下文,但是你可以直接示例化你的类,避免了由于@Async而导致的代理。测试将更容易和更快。
@Async属于框架,通常框架特性不应在单元测试的范围内(而它们可以用于组件/集成测试)。
Spring的一篇博客文章也建议:
对Spring @Component进行单元测试的最简单的方法就是完全不涉及Spring!最好的方法是尝试并构建代码,以便类可以被示例化并直接测试。通常这可以归结为几件事:

  • 用清晰的关注点分离来组织你的代码,这样单个部分就可以进行单元测试。TDD是实现这一点的好方法。
  • 使用构造函数注入来确保对象可以直接示例化。不要使用字段注入,因为它只会使你的测试更难编写。

相关问题