繁体   English   中英

尝试集成测试 spring-data-jpa 抛出 MockMVC,但更新不起作用

[英]Try integration test spring-data-jpa throw MockMVC, but update does not work

我使用 spring-data-jpa 和 spring-boot-web 构建了一个演示应用程序。 我尝试使用 MockMVC 构建集成测试,它将调用添加接口,然后是修改接口,最后是查询接口,并确定更改是否生效。 我还使用“spring.jpa.properties.hibernate.show_sql”属性,打印 sql 登录控制台。 但是,在控制台中,我只看到了一个insert sql,一个query sql,没有看到update sql。另外,我使用的@PreUpdate 注解没有生效,因为覆盖率检查显示没有执行。

但是当我通过 postman 测试时,一切都非常正常并且符合预期:我看到更新 sql 并且它也执行了@PreUpdate。

编写测试用例时我做错了什么?

这是我的测试代码。 Rest Api 只是调用JpaRepository。

@ExtendWith(SpringExtension.class)
@AutoConfigureMockMvc(addFilters = false)
@SpringBootTest
@Transactional
class TechyoControllerTest {
    @Autowired
    private MockMvc mockMvc;
    @Autowired
    private ObjectMapper objectMapper;

    @SneakyThrows
    @Test
    public void should_update_success() {
        String createRequest = "{\"name\":\"name_test\",\"money\":12.3}";
        MvcResult mvcCreateResult = mockMvc
                .perform(MockMvcRequestBuilders.post("/accountItems")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(createRequest))
                .andReturn();
        AccountItemResponse createResult =
                objectMapper.readValue(mvcCreateResult.getResponse().getContentAsString(), AccountItemResponse.class);

        // update
        String updateRequest = "{" +
                "  \"name\": \"updated_name\"," +
                "  \"date\": " + createResult.getTransactionTime().getTime() + "," +
                "  \"lines\": [{" +
                "    \"name\": \"line1\"," +
                "    \"money\": 12" +
                "  }, {\n" +
                "    \"name\": \"line1\"," +
                "    \"money\": 12" +
                "  }, {\n" +
                "    \"name\": \"line1\"," +
                "    \"money\": -12" +
                "  }]" +
                "}";
        MvcResult mvcUpdateResult = mockMvc
                .perform(MockMvcRequestBuilders.put("/accountItems/" + createResult.getId())
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(updateRequest))
                .andExpect(status().isOk())
                .andReturn();
        AccountItemResponse updateResult
                = objectMapper.readValue(mvcUpdateResult.getResponse().getContentAsString(), AccountItemResponse.class);
        assertThat(updateResult.getId()).isEqualTo(createResult.getId());
        assertThat(updateResult.getTransactionTime()).hasSameTimeAs(createResult.getTransactionTime());
        assertThat(updateResult.getTotal()).isEqualTo(new BigDecimal("12.00"));
        assertThat(updateResult.getAccountItemLines()).hasSize(3);

        // query
        MvcResult mvcGetResult = mockMvc
                .perform(MockMvcRequestBuilders.get("/accountItems/" + createResult.getId()))
                .andExpect(status().isOk())
                .andReturn();
        AccountItemResponse getResult
                = objectMapper.readValue(mvcGetResult.getResponse().getContentAsString(), AccountItemResponse.class);
        assertThat(getResult.getId()).isEqualTo(createResult.getId());
        assertThat(getResult.getTransactionTime()).hasSameTimeAs(createResult.getTransactionTime());
        assertThat(getResult.getTotal()).isEqualTo(new BigDecimal("12.00"));
        assertThat(getResult.getAccountItemLines()).hasSize(3);
    }
}

这是我的实体代码

@MappedSuperclass
@Getter
@Setter
@RequiredArgsConstructor
@Accessors(chain = true)
public class BasePO {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column(updatable = false, nullable = false)
    @Temporal(TemporalType.TIMESTAMP)
    private Date createTime;
    @Column(nullable = false)
    @Temporal(TemporalType.TIMESTAMP)
    private Date updateTime;

    @PrePersist
    protected void prePersist() {
        Date now = new Date();
        if (createTime == null) {
            createTime = now;
        }
        if (updateTime == null) {
            updateTime = now;
        }
    }

    @PreUpdate
    protected void preUpdate() {
        updateTime = new Date();
    }

    @PreRemove
    protected void preRemove() {
        updateTime = new Date();
    }
}
@Entity
@Table(name = "account_item")
@Accessors(chain = true)
@Getter
@Setter
@RequiredArgsConstructor
public class AccountItemPO extends BasePO {
    @Column(nullable = false)
    private String name;
    @Column(nullable = false, columnDefinition = "decimal(10,2)")
    private BigDecimal totalMoney;
    private Date transactionTime;
}

这个集成测试本身并没有抛出任何异常(因为我返回的数据不包含updateTime等字段)。 程序执行加断点显示确实更新了数据,但是create_time/update_time设置为null(虽然我用的是nullable = false)

这是从控制台打印的 sql

Hibernate: 
    insert 
    into
        account_item
        (create_time, update_time, name, total_money, transaction_time) 
    values
        (?, ?, ?, ?, ?)

Hibernate: 
    select
        count(*) as col_0_0_ 
    from
        account_item accountite0_ 
    where
        accountite0_.id=?

也许你可以试试这个解决方案。 它适用于 Spring Boot 2.7.5(包括 GraphQL)

https://github.com/graphql-java/graphql-java-spring/issues/30#issuecomment-860026650

Handler:
         Type = org.springframework.boot.autoconfigure.graphql.servlet.GraphQlWebMvcAutoConfiguration$$Lambda$1547/1627578183 Async:
Async started = true
 Async result = org.springframework.web.servlet.function.DefaultEntityResponseBuilder$DefaultEntityResponse@3ec151c5

不知何故,我看到日志说 async = true。 所以我认为关键是等待异步完成

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM