@SpringBootTest: @MockBean не внедряется при нескольких тестовых классах - PullRequest
2 голосов
/ 14 июля 2020

Я хочу написать тесты контроллера, которые также проверяют мои аннотации. До сих пор я читал, что RestAssured - один из способов go.

Он работает плавно, когда у меня есть только один тест контроллера. Однако при наличии 2 или более тестовых классов контроллеров @MockBeans, похоже, не используются должным образом. В зависимости от порядка выполнения тестов все тесты из первого тестового класса завершаются успешно, а все остальные - нет.

В следующем тестовом прогоне сначала был выполнен PotatoControllerTest, а затем FooControllerTest.

@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles({"test", "httptest"})
class FooControllerTest {

    @MockBean
    protected FooService mockFooService;

    @MockBean
    protected BarService mockBarService;

    @LocalServerPort
    protected int port;

    @BeforeEach
    public void setup() {
        RestAssured.port = port;
        RestAssured.authentication = basic(TestSecurityConfiguration.ADMIN_USERNAME, TestSecurityConfiguration.ADMIN_PASSWORD);
        RestAssured.requestSpecification = new RequestSpecBuilder()
                .setContentType(ContentType.JSON)
                .setAccept(ContentType.JSON)
                .build();
    }

    @SneakyThrows
    @Test
    void deleteFooNotExists() {
        final Foo foo = TestUtils.generateTestFoo();
        Mockito.doThrow(new DoesNotExistException("missing")).when(mockFooService).delete(foo.getId(), foo.getVersion());

        RestAssured.given()
                .when().delete("/v1/foo/{id}/{version}", foo.getId(), foo.getVersion())
                .then()
                .statusCode(HttpStatus.NOT_FOUND.value());
        Mockito.verify(mockFooService, times(1)).delete(foo.getId(), foo.getVersion());
    }

...
}
@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles({"test", "httptest"})
class PotatoControllerTest {

    @MockBean
    protected PotatoService mockPotatoService;

    @LocalServerPort
    protected int port;

    @BeforeEach
    public void setup() {
        RestAssured.port = port;
        RestAssured.authentication = basic(TestSecurityConfiguration.ADMIN_USERNAME, TestSecurityConfiguration.ADMIN_PASSWORD);
        RestAssured.requestSpecification = new RequestSpecBuilder()
                .setContentType(ContentType.JSON)
                .setAccept(ContentType.JSON)
                .build();
    }

...

}
Wanted but not invoked:
fooService bean.delete(
    "10e76ae4-ec1b-49ce-b162-8a5c587de2a8",
    "06db13f1-c4cd-435d-9693-b94c26503d40"
);
-> at com.xxx.service.FooService.delete(FooService.java:197)
Actually, there were zero interactions with this mock.

Я попытался исправить это с помощью обычного ControllerTestBase, который настраивает все макеты и все другие тесты контроллера, расширяющие базовый класс. Что отлично работало на моей машине, но, например, не в стадии разработки. Так что я думаю, что это не совсем стабильно.

Почему Spring не перезагружает контекст с помощью моков? Это «лучший» способ тестирования моих контроллеров?

1 Ответ

1 голос
/ 14 июля 2020

Было бы намного проще и быстрее просто использовать Mock Mvc.

Вы можете просто создать автономную настройку для желаемого контроллера и выполнить дополнительную настройку (например, настройка исключения резольверы). Также вы можете легко вводить свои макеты:

@Before
public void init() {
  MyController myController = new MyController(mock1, mock2, ...);
  MockMvc mockMvc = 
  MockMvcBuilders.standaloneSetup(myController)
                 .setHandlerExceptionResolvers(...)
                 .build();
}

После этого вы можете легко вызывать свои конечные точки:

MvcResult result = mockMvc.perform(
            get("/someApi"))
             .andExpect(status().isOk)
             .andReturn();

Дополнительная проверка ответа может быть выполнена, как вы уже знаете .

Edit : В качестве примечания - это сделано для явного тестирования вашего веб-слоя. Если вы хотите go для какого-то интеграционного теста, идущего дальше вниз в стеке вашего приложения, также охватывающего бизнес-логию c, это неправильный подход.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...