SpringBootTest不会回滚

时间:2019-06-07 11:54:52

标签: spring-boot integration-testing

(尽管有很多类似的问题我无法在其中找到解决方案)。

为什么当我直接使用@Transactional时,带有@SpringBootTest的{​​{1}}注释可以正常工作并回滚,但是当我使用DAO进行测试时却不能正常工作?

tl; dr

实体
TestRestTemplate
资料库
@Entity
public class ToDoItem {
  @Id @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;
  @NotNull @Column(unique = true)
  private String title;

  public ToDoItem() {}

  public ToDoItem(String title) { this.title = title;}
  // getters, setters, etc.
应用
public interface ToDoRepository extends CrudRepository<ToDoItem, Long> {}

现在,我创建两个基本相同的测试:将一些待办事项存储在内存数据库中,并检查大小是否增加:

仓库测试
@EnableTransactionManagement
@SpringBootApplication
@RestController
@RequestMapping("/todos")
public class ToDoApp {

    public static void main(String[] args) {
        SpringApplication.run(ToDoApp.class, args);
    }

    @Autowired
    private ToDoRepository toDoRepository;

    @GetMapping
    ResponseEntity<?> fetchAll() { return ok(toDoRepository.findAll()); }

    @PostMapping()
    ResponseEntity<?> createNew(@RequestBody ToDoItem toDoItem) {
        try {
            toDoRepository.save(toDoItem);
            return noContent().build();
        } catch (Exception e) {
            return badRequest().body(e.getMessage());
        }
    }
}

然后,我通过REST API创建一个功能完全相同的相似测试(此测试不起作用,并且失败,并@ExtendWith(SpringExtension.class) @SpringBootTest @Transactional class ToDoRepoTests { @Autowired private ToDoRepository toDoRepository; @Test void when_adding_one_item_then_success() { toDoRepository.save(new ToDoItem("Run tests")); assertThat(toDoRepository.findAll()).hasSize(1); } @Test void when_adding_two_items_then_success() { toDoRepository.saveAll(List.of( new ToDoItem("Run tests"), new ToDoItem("Deploy to prod"))); assertThat(toDoRepository.findAll()).hasSize(2); } } 失败):

Unique index or primary key violation

这是我的@ExtendWith(SpringExtension.class) @SpringBootTest(classes = ToDoApp.class, webEnvironment = WebEnvironment.RANDOM_PORT) @Transactional class ToDoControllerTests { @LocalServerPort private int localServerPort; private TestRestTemplate testRestTemplate; @BeforeEach void setUp() { testRestTemplate = new TestRestTemplate(new RestTemplateBuilder() .rootUri("http://localhost:" + localServerPort)); } @Test void when_adding_one_item_then_success() { // when createToDo(new ToDoItem("Walk the dog")); var allItems = fetchAllTodos(); // then assertThat(allItems).hasSize(1); } @Test void when_adding_two_items_then_success() { // when createToDo(new ToDoItem("Walk the dog")); createToDo(new ToDoItem("Clean the kitchen")); var allItems = fetchAllTodos(); // then assertThat(allItems).hasSize(2); } private void createToDo(ToDoItem entity) { var headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); var response = testRestTemplate.postForEntity("/todos", new HttpEntity<>(entity, headers), String.class); assertThat(response.getStatusCode()).isEqualTo(NO_CONTENT); } private List<ToDoItem> fetchAllTodos() { return Arrays.asList(testRestTemplate.getForObject("/todos", ToDoItem[].class)); } }

pom.xml

请,帮助我了解我在做什么错。

1 个答案:

答案 0 :(得分:1)

当您使用RESTTemplate调用API时,它将越过本地事务管理的边界,并成为分布式事务。 spring没有可用的机制来回滚对其余API的调用。尽管在您的示例中目标系统是相同的应用程序,但不必如此。可能是一个外部应用程序,它不知道您在测试中设置的事务边界。