Как я могу протестировать контроллер Spring, использующий JDB C? - PullRequest
2 голосов
/ 10 июля 2020

У меня есть контроллер Spring, который выглядит так:

@RestController
@RequestMapping("/foo")
public class FooController {
    @Autowired
    private NamedParameterJdbcTemplate template;

    @GetMapping("/{name}")
    public List<Foo> byName(@PathVariable String name) {
        Map<String, String> params = new HashMap<>();
        params.put("name", name);
        List<Foo> result = template.query("SELECT * FROM FOOS WHERE FOO_NM = :name", params, new FooRowMapper());
        if (result.size() == 0) {
            throw new ResponseStatusException(HttpStatus.NOT_FOUND, String.format("foo %s not found", name));
        }
        return result;
    }
}

Однако я не уверен, как это проверить. Я могу выполнить базовый тест c «Spring может настроить его»:

@SpringBootTest
public class FooControllerTest {
    @Autowired
    private FooController controller;

    @Test
    public void canCreate() {
        Assertions.assertNotNull(controller);
    }
}

Но я не уверен, как правильно проверить, например, метод byName. Надо что-то издеваться? Могу ли я просто протестировать его как простой метод Java (вызвать его с любыми параметрами и подтвердить результат)?

Ответы [ 5 ]

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

Это плохая идея делать контроллер, который использует сам JDB C. Намного лучше использовать Controller-Service-Repository pattern.

Таким образом, ваш код в контроллере Foo может быть таким:

@RestController
@RequestMapping("/foo")
public class FooController {
  @Autowired
  private FooService fooService;
  
  @GetMapping("/{name}")
  public ResponseEntity<?> byName(@PathVariable String name) {
    final List<Foo> list = fooService.getFooByName(name);
    return ResponseEntity.ok(list);
  }
}

В целях тестирования лучше использовать Mock Mvc:

// In the Foo controller
@GetMapping("/{name}")
    public ResponseEntity<?> byName(@PathVariable String name) {
        return ResponseEntity.ok("Hello, " + name);
}

// In the Test class
@SpringBootTest
@AutoConfigureMockMvc
class ControllerTests {
    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private FooController fooController;

    @Test
    public void contextLoads() {
        assertThat(fooController, is(notNullValue()));
    }

    @Test
    public void getUser() throws Exception {
        MockHttpServletResponse response = mockMvc.perform(MockMvcRequestBuilders.get("/foo/Joe"))
                .andExpect(status().isOk())
                .andDo(print())
                .andReturn().getResponse();

        assertThat(response.getContentAsString(), is("Hello, Joe"));
    }

}
1 голос
/ 10 июля 2020

Я совсем не лучший для тестирования своих контроллеров (я тоже начал не слишком долго go) И хорошо, я создаю макет своего контроллера.

class UserControllerTest {

@Autowired
private MockMvc mockMvc;

@Test
void addUserTest() throws Exception {
    String content = "{" +
            "\"username\": \"test\"," +
            "\"password\": \"tesT1234\"," +
            "\"email\": \"test@test.com\"" +
            "}";

    mockMvc.perform(
            MockMvcRequestBuilders.post("/users/signup")
                    .contentType(MediaType.APPLICATION_JSON)
                    .content(content))
            .andExpect(status().isCreated());
}

Например, здесь для регистрации пользователь, я создаю контент JSON и отправляю его в свой макет. Я проверяю окончательный статус, чтобы увидеть, создает ли он пользователя.

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

Надо ли что-то издеваться?

Смотря что именно нужно тестировать. Если вы пишете модульный тест - тогда вы обычно имитируете внешние зависимости, предполагая, что они будут следовать какому-то контракту.

Могу я просто протестировать его как простой метод Java параметры и подтвердите вывод)?

Конечно, можете, но это будет означать, что вы тестируете метод bean-компонента, но не полный поток от получения http-запроса и возврата ответа.

Если вам нужно выполнить сквозной тест, вам нужно запустить приложение, а затем вызвать методы HTTP и проверить ответ. Для этого вы можете использовать Mock Mvc, как описано в одном из ответов.

0 голосов
/ 10 июля 2020

После небольшого исследования и помощи из опубликованных ответов я переместил код поиска в службу:

@Service
public class FooService implements IFooService {
    @Autowired
    private NamedParameterJdbcTemplate template;

    // the only method of IFooService
    @Override
    public List<FormulaFunction> getAllByName(String name) {
        Map<String, String> params = new HashMap<>();
        params.put("name", name);
        return template.query("SELECT * FROM FOOS WHERE FOO_NM = :name", params, new FooRowMapper());
    }
}

При тестировании контроллера эта служба имитируется с помощью Mockito:

@WebMvcTest(FooController.class)
public class FooControllerTest {
    @MockBean
    private IFooService service;

    @Autowired
    private FooController controller;

    @Autowired
    private MockMvc mvc;

    @Test
    public void canCreate() {
        Assertions.assertNotNull(controller);
    }

    /**
     * Test that controller properly returns 404 when no results are found
     */
    @Test
    public void test404() throws Exception {
        doReturn(new ArrayList<>()).when(service).getAllByName("bars");
        this.mvc.perform(get("/foo/bars")).andExpect(status().isNotFound());
    }
}
0 голосов
/ 10 июля 2020

Вы можете протестировать его как обычный метод Java или использовать Mock Mvc для выполнения запроса на получение соответствующего пути.

Было бы неплохо, если бы вы опубликовали тело своего метода (справа теперь трудно помочь).

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