配置Spring JUnit 5测试精确性

huangapple go评论71阅读模式
英文:

Percisely configure spring junit 5 test config

问题

以下是您提供的内容的中文翻译:

使用spring-boot和junit5编写单元测试一直有些困难
我已经阅读了许多文章以及一些junit5的文档但没有找到任何有帮助的内容或者我可能看漏了)。

测试代码

@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = ScoreTestConfiguration.class)
@AutoConfigureMockMvc
public class ScoreControllerTest {

private static final String SCORE_ENDPOINT = "/scoring";

private static final ObjectMapper MAPPER = new ObjectMapper();

@Autowired
private MockMvc mockMvc;
@MockBean
private ScoreService mockScoreService;

@BeforeEach
public void setUp() {
    ScoreResponseDto response = getScoreResponseDto();
    when(mockScoreService.getScore(any(), any(), any(), any(), any(), any())).thenReturn(response);
}

@NotNull
private ScoreResponseDto getScoreResponseDto() {
    ScoreResponseDto response = new ScoreResponseDto();
    response.setCid("qwe13423qw");
    response.setData(new ScoreResponseDto.ScoringData(0.78f));
    return response;
}

@Test
public void sendValidRequest_getResponse_andOkStatus() throws Exception {
    String request = SCORE_ENDPOINT +
            "/380715346789" + //msisdn
            "?score_formula=1234" +
            "&clientId=5678" +
            "&cid=543" +
            "&stateType=" + StateType.ACTIVE.name() +
            "&subscriberType=" + SubscriberType.POSTPAID.getValue();
    String jsonResponse = MAPPER.writeValueAsString(getScoreResponseDto());
    System.out.println("jsonResponse: " + jsonResponse);
    mockMvc.perform(get(request))
            .andDo(print())
            .andExpect(status().isOk())
            .andExpect(content().string(jsonResponse));
}
}

配置这是一个试验只获取某些类但我失败了):

@Configuration
@ComponentScan(basePackages = "com.some.path.to.rest")
class ScoreTestConfiguration {

}

在执行测试时我假设全局上下文已被初始化尽管我在@Configuration类中指定了仅加载其中的一部分

我的问题是如何控制和设置spring-boot和junit5测试的精确测试上下文配置

实际上如果有人能提供一些有关如何组织本地测试框架的最佳实践的参考资料我将非常感激
提前谢谢

请注意,我已根据您的要求仅返回了翻译的部分,没有额外的内容。

英文:

Struggling for quite some with writing unit tests with spring-boot and junit5.
I've read lots of articles and some of the junit5 documentation but didn't find anything that would help (or I'm just blind).

test:

@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = ScoreTestConfiguration.class)
@AutoConfigureMockMvc
public class ScoreControllerTest {
private static final String SCORE_ENDPOINT = "/scoring";
private static final ObjectMapper MAPPER = new ObjectMapper();
@Autowired
private MockMvc mockMvc;
@MockBean
private ScoreService mockScoreService;
@BeforeEach
public void setUp() {
ScoreResponseDto response = getScoreResponseDto();
when(mockScoreService.getScore(any(),any(),any(),any(),any(),any())).thenReturn(response);
}
@NotNull
private ScoreResponseDto getScoreResponseDto() {
ScoreResponseDto response = new ScoreResponseDto();
response.setCid("qwe13423qw");
response.setData(new ScoreResponseDto.ScoringData(0.78f));
return response;
}
@Test
public void sendValidRequest_getResponse_andOkStatus() throws Exception {
String request = SCORE_ENDPOINT +
"/380715346789" + //msisdn
"?score_formula=1234" +
"&clientId=5678" +
"&cid=543" +
"&stateType=" + StateType.ACTIVE.name() +
"&subscriberType=" + SubscriberType.POSTPAID.getValue();
String jsonResponse = MAPPER.writeValueAsString(getScoreResponseDto());
System.out.println("jsonResponse: " + jsonResponse);
mockMvc.perform(get(request))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().string(jsonResponse));
}

}

configuration (it's an experiment to get only certain only certain classes but I failed):

@Configuration
@ComponentScan(basePackages = "com.some.path.to.rest")
class ScoreTestConfiguration {
}

While test execution , I assume, that global context is been initiated despite that I specified to load only part of it in @Configuration class.

My question how can I control and setup precise configuration of test context for spring-boot and junit5 test.

Actually if somebody will give some references about best practices hot to organize local testing framework I'll be really grateful.
Thank you in advance!

答案1

得分: 1

以下是翻译好的内容:


没有看到更多的您的代码,很难确定为什么您的测试配置不满足您的需求。我创建了一个示例项目,其中包含几个类似于您的情况以及其他一些示例 - 您可以在GitHub上找到它。以下是您可以在那里找到的示例列表,附有简短的描述。


@SpringBootTest(classes = TestedController.class)
@AutoConfigureMockMvc
public class TestWithoutConfiguration {

    @Test
    void fails() {

    }

}

这个测试失败了,因为除了控制器bean之外,没有提供任何配置 - 无法找到和注入任何bean。


@SpringBootTest(classes = {TestedController.class, TestConfiguration.class})
@AutoConfigureMockMvc
public class TestWithTestButWithoutMockBeanConfiguration {

    @Test
    void fails() {

    }

}

在这里,我们使用一个测试配置为我们的控制器提供了一个服务bean,但我们仍然缺少该服务使用的bean - MockedUtilInterface(见下文)。


@SpringBootTest(classes = {TestedController.class, TestConfiguration.class})
@AutoConfigureMockMvc
public class TestWithTestConfiguration {

    @Autowired
    private MockMvc mockMvc;
    @MockBean
    private MockedUtilInterface mockedUtil;

    @Test
    void test() throws Exception {
        when(mockedUtil.value())
                .thenReturn(100);

        mockMvc.perform(get("/test"))
               .andExpect(content().string("100 - rest service from component scan value"));
    }

}

这个测试通过了 - TestConfiguration提供了服务bean,我们还创建了一个MockedUtilInterface bean作为模拟。模拟被注入到测试配置指向的服务中,然后将服务注入到实际控制器中。


@SpringBootTest
@AutoConfigureMockMvc
public class TestWithActualConfiguration {

    @Autowired
    private MockMvc mockMvc;

    @Test
    void test() throws Exception {
        mockMvc.perform(get("/test"))
               .andExpect(content().string("0 - not a test value"));
    }

}

这个测试也通过了,它使用所有实际配置,不加载测试配置,因此所有bean都是我们实际应用程序的bean(就好像它在容器中运行一样)。


@SpringBootTest
@AutoConfigureMockMvc
public class TestWithInnerTestConfiguration {

    @Configuration
    @Import(TestedApplication.class)
    static class InnerConfiguration {

        @Bean
        TestedServiceInterface service(MockedUtilInterface mockedUtil) {
            return () -> mockedUtil.value() + " - inner value";
        }

    }

    @Autowired
    private MockMvc mockMvc;
    @MockBean
    private MockedUtilInterface mockedUtil;

    @Test
    void test() throws Exception {
        when(mockedUtil.value())
                .thenReturn(12345);

        mockMvc.perform(get("/test"))
               .andExpect(content().string("12345 - inner value"));
    }

}

这是一个内部类配置的示例,可以覆盖一些bean,使用一些实际bean,并且还可以使用提供的@MockBeans


这里您可以找到为测试配置bean的多种方法。

英文:

Without seeing more of your code, it's hard to tell why your test configuration does not meet your needs. I've created a sample project with a few different examples similar to your case and some other - you can find it here on GitHub. Below is the list of examples you can find there with a short description.


@SpringBootTest(classes = TestedController.class)
@AutoConfigureMockMvc
public class TestWithoutConfiguration {
@Test
void fails() {
}
}

This test fails, since no configuration (apart from the controller bean) is provided - no beans can be found and injected.


@SpringBootTest(classes = {TestedController.class, TestConfiguration.class})
@AutoConfigureMockMvc
public class TestWithTestButWithoutMockBeanConfiguration {
@Test
void fails() {
}
}

Here we use a test configuration that provides a service bean for our controller, but we still lack a bean used by that service - MockedUtilInterface (see below).


@SpringBootTest(classes = {TestedController.class, TestConfiguration.class})
@AutoConfigureMockMvc
public class TestWithTestConfiguration {
@Autowired
private MockMvc mockMvc;
@MockBean
private MockedUtilInterface mockedUtil;
@Test
void test() throws Exception {
when(mockedUtil.value())
.thenReturn(100);
mockMvc.perform(get("/test"))
.andExpect(content().string("100 - rest service from component scan value"));
}
}

This test passes - TestConfiguration provides the service bean and we're also creating a MockedUtilInterface bean as a mock. The mock is injected into the service to which the test configuration points and the service is injected into the actual controller.


@SpringBootTest
@AutoConfigureMockMvc
public class TestWithActualConfiguration {
@Autowired
private MockMvc mockMvc;
@Test
void test() throws Exception {
mockMvc.perform(get("/test"))
.andExpect(content().string("0 - not a test value"));
}
}

This test also passes and it uses all the actual configuration, no test configuration is loaded, so all the beans are the beans from our actual application (as if it was run in a container).


@SpringBootTest
@AutoConfigureMockMvc
public class TestWithInnerTestConfiguration {
@Configuration
@Import(TestedApplication.class)
static class InnerConfiguration {
@Bean
TestedServiceInterface service(MockedUtilInterface mockedUtil) {
return () -> mockedUtil.value() + " - inner value";
}
}
@Autowired
private MockMvc mockMvc;
@MockBean
private MockedUtilInterface mockedUtil;
@Test
void test() throws Exception {
when(mockedUtil.value())
.thenReturn(12345);
mockMvc.perform(get("/test"))
.andExpect(content().string("12345 - inner value"));
}
}

And here's an example of an inner class configuration that overrides some beans, uses some actual beans and can also make use of provided @MockBeans.


Here you can find quite a few ways to configure the beans for a test.

huangapple
  • 本文由 发表于 2020年8月10日 22:43:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/63342469.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定