Весна, другое поведение при тестировании - PullRequest
1 голос
/ 23 марта 2019

Я экспериментирую с Spring Web и тестирую контроллер REST. Приложение в основном представляет собой игровую базу данных, доступную через веб-сервис.

Когда я запускаю его и тестирую вместе с Почтальоном, чтобы добавить игру, я получаю искомое поведение. Однако, когда я тестирую контроллер с помощью SpringJUnit4ClassRunner, кажется, что игра, которую я пытаюсь добавить, уже существует в базе данных, и я не могу добавить ее.

Вот мой тестовый класс:

@RunWith(SpringJUnit4ClassRunner.class)
@WebMvcTest(GameController.class)
public class GameControllerTest {

    @MockBean
    private IGameService gameService;

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void postGameTest() throws Exception {
        String mockGameJson = "{\"name\":\"Test Game\",\"description\":\"A test game.\"}";

        //Create a post request with an accept header for application\json
        RequestBuilder requestBuilder = MockMvcRequestBuilders
                .post("/game/")
                .accept(MediaType.APPLICATION_JSON).content(mockGameJson)
                .contentType(MediaType.APPLICATION_JSON);

        MvcResult result = mockMvc.perform(requestBuilder).andReturn();

        MockHttpServletResponse response = result.getResponse();

        //Assert that the return status is CREATED
        assertEquals(HttpStatus.CREATED.value(), response.getStatus());
    }
}

Утверждение в последней строке не выполнено, так как статус http 409 Conflict

Я лично возвращаю этот статус в контроллере:

@RestController
public class GameController {

    @Autowired
    private IGameService gameService;

    @PostMapping("/game")
    public ResponseEntity<String> addGame(@RequestBody Game game, UriComponentsBuilder builder) {
        boolean flag = gameService.addGame(game);
        if (!flag) return new ResponseEntity<>("Another game with this name already exists.", HttpStatus.CONFLICT);
        HttpHeaders headers = new HttpHeaders();
        headers.setLocation(builder.path("/game/{id}").buildAndExpand(game.getId()).toUri());
        return new ResponseEntity<>(headers, HttpStatus.CREATED);
    }
...

Не имеет смысла, что это произойдет, потому что моя база данных должна быть пустой в начале теста, верно? Вот соответствующий сервис:

@Service
public class GameService implements IGameService { //Service layer

    @Autowired
    private IGameDAO gameDAO;

    @Override
    public synchronized boolean addGame(Game game) {
        if(gameDAO.gameExists(game.getName()))
            return false;
        else {
            gameDAO.addGame(game);
            return true;
        }
    }
...

И DAO:

@Transactional
@Repository
public class GameDAO implements IGameDAO {

    @PersistenceContext
    private EntityManager entityManager;


    @Override
    public void addGame(Game game) {
        entityManager.persist(game);
    }

    @Override
    public boolean gameExists(String name) {
        String jpql = "from Game as g WHERE g.name = ?0 ";
        int count = entityManager.createQuery(jpql).setParameter(0, name).getResultList().size();
        return count > 0;
    } ...

И это зависимости в моем build.gradle

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'com.h2database:h2'

    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

Что я здесь не так делаю?

1 Ответ

0 голосов
/ 23 марта 2019

Решил это. Как было отмечено, лучше тестировать слои независимо друг от друга. Здесь я пытался проверить мой контроллер (веб). Служба проверяется, поэтому по умолчанию любой вызов метода, который должен возвращать логическое значение, будет возвращать значение false.

Мне пришлось сказать проверенному сервису вернуть true, чтобы адекватно протестировать метод post. Вот так:

given(gameService.addGame(any())).willReturn(true);
...