【问题标题】:Spring, different behaviour when testingSpring,测试时的不同行为
【发布时间】:2019-03-23 00:46:47
【问题描述】:

我正在试验 Spring Web 并测试 REST 控制器。 该应用程序基本上是一个可通过 Web 服务访问的游戏数据库。

当我启动它并使用 Postman 对其进行测试以添加游戏时,我得到了我正在寻找的行为。 但是,当我使用 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 冲突

我个人在控制器中返回该状态:

@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'
}

我在这里做错了什么?

【问题讨论】:

  • 我认为由于您使用的是@MockBean 而不是实际的 bean,因此自动装配的 DAO 存储库只是被模拟了,而不是实际使用。如果您想测试 Repo,请在测试中明确测试 repos 方法。在测试 Spring 应用程序时,明智的做法是单独测试每一层(数据、Web、服务)。

标签: spring spring-test spring-web spring-test-mvc


【解决方案1】:

解决了。 正如评论的那样,最好独立测试图层。 在这里,我试图测试我的控制器(网络)。该服务是模拟的,因此默认情况下,对应该返回布尔值的方法的任何调用都将返回 false。

我必须告诉模拟服务返回 true 以充分测试 post 方法。像这样:

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

【讨论】:

    猜你喜欢
    • 2018-12-02
    • 2019-09-14
    • 2021-06-10
    • 1970-01-01
    • 2015-03-22
    • 2013-05-17
    • 1970-01-01
    • 2019-08-17
    • 1970-01-01
    相关资源
    最近更新 更多