10

Tôi muốn thử nghiệm phương thức save() của hibernate session bằng cách sử dụng khung kiểm thử mùa xuân. @Test method is:Làm thế nào để tuôn ra dữ liệu vào db bên trong giao dịch mùa xuân đang hoạt động?

@Test 
@Transactional 
public void testSave() { 
User expected = createUser(); 
getGenericDao().currentSession().save(expected); 
User actual = getUser(generatedId); 
assertUsersEqual(expected,actual); 
} 

Tôi muốn xóa người dùng vào cơ sở dữ liệu. Tôi muốn người dùng của tôi là trong cơ sở dữ liệu sau khi phương pháp này

getGenericDao().currentSession().save(expected); 

Sau đó, tôi muốn đi đến cơ sở dữ liệu sử dụng khung dữ liệu mùa xuân và lấy này lưu người dùng bằng dòng tiếp theo:

User actual = getUser(generatedId); 

Tôi cố gắng để sử dụng hibernate phương pháp tuôn ra như:

currentSession().setFlushMode(MANUAL); 
//do saving here 
currentSession().flush(); 

Nó không xóa người dùng của tôi vào cơ sở dữ liệu! Tuy nhiên, nếu tôi không sử dụng chú thích mùa xuân @Transactional và lưu người dùng của tôi trong giao dịch mùa xuân có lập trình, tôi sẽ đạt được những gì tôi muốn. Rất tiếc, người dùng được lưu vào db không được khôi phục vì không có @Transactional mùa xuân. Do đó phương pháp thử nghiệm của tôi thay đổi db và hành vi của các phương pháp thử nghiệm tiếp theo.

Vì vậy, tôi cần xóa người dùng của mình thành phương pháp thử nghiệm bên trong db (không phải ở cuối) và ở cuối phương thức kiểm tra, tất cả thay đổi đối với db.

CẬP NHẬT gợi ý để chuẩn bị phương pháp như sau:

@Transactional 
public void doSave(User user){ 
    getGenericDao().currentSession().save(user); 
} 

Và gọi doSave bên testSave đang làm gì. Tôi vẫn không có người dùng trong db sau khi thực hiện phương pháp này. Tôi đặt breakpoint và kiểm tra db của tôi từ dòng lệnh.

CẬP NHẬT Cảm ơn rất nhiều vì đã trả lời. Vấn đề là phương thức flush() không đưa người dùng của tôi vào cơ sở dữ liệu. Tôi đã thử Isolation.READ_UNCOMMITTED và nó không đưa người dùng của tôi vào cơ sở dữ liệu. Tôi có thể đạt được những gì tôi muốn nhưng chỉ khi tôi tắt giao dịch mùa xuân trên phương thức @Test và thực hiện lưu trong giao dịch có lập trình. NHƯNG sau đó phương pháp @Test không được cuộn lại để lại người dùng đã lưu cho các phương thức @Test tiếp theo. Ở đây phương pháp @Test để lưu người dùng không phải là nguy hiểm như phương pháp @Test để xóa người dùng, bởi vì nó không được quay trở lại. Vì vậy, phải có hỗ trợ giao dịch cho phương thức @Test mà tôi không thể đưa người dùng của tôi (hoặc xóa) vào db. Trên thực tế người dùng được đặt (hoặc xóa) vào db chỉ sau khi phương thức @Test kết thúc và giao dịch cho phương thức @Test được đính kèm. Vì vậy, tôi muốn lưu Người dùng của tôi vào db ở giữa phương pháp @Test và quay lại vào cuối phương pháp @Test

Cảm ơn bạn!

+0

Bạn có thể cung cấp cho chúng tôi lớp GenericDao của bạn không? EDIT: thực sự, tôi nghĩ rằng tôi thấy vấn đề. Giao dịch hiện tại cần phải được cam kết trước khi dữ liệu thực sự được lưu vào cơ sở dữ liệu. Vì vậy, bạn cần hai phương pháp @Transactional: một để lưu và một phương pháp khác để tải. –

+0

Hãy nhìn xem nếu tôi đã làm đúng –

+0

Đóng. Tôi có nghĩa là có hai chức năng giao dịch được gọi là bởi một chức năng phi giao dịch. Điều đó sẽ làm việc ... –

Trả lời

1

Nếu flush không hoạt động thì điều đó phụ thuộc rất nhiều vào cấp độ cách ly cơ sở dữ liệu của bạn.

Isolation là một trong số ACID thuộc tính của cơ sở dữ liệu, xác định cách thức/khi các thay đổi được thực hiện bởi một thao tác sẽ hiển thị với các hoạt động đồng thời khác.

Tôi tin mức độ cách ly của bạn được đặt thành Read Committed hoặc Repeatable Read.

8

Cuối cùng tôi bị mắc kẹt với các giải pháp sau đây:

Thứ nhất, @Test phương pháp của tôi không chạy trong hỗ trợ mùa xuân @Transactional. Xem this article để biết mức độ nguy hiểm của nó. Tiếp theo, thay vì sử dụng @Repository đậu trong các phương thức @Test Tôi autowire @Service đậu sử dụng chú thích @Transactional. Phép lạ là @Test phương pháp như thế này

@Test 
@Transactional(propagation = Propagation.NOT_SUPPORTED) 
public void testSave() { 
    Answer created = createAnswer(); 
    Long generatedId = answerService.save(created); 
//at this moment answer is already in db 
    Answer actual=getAnswerById(generatedId); 
... } 

đặt đối tượng trả lời của tôi vào cơ sở dữ liệu (chỉ sau answerService.save(created);) và phương pháp getAnswerById đi vào DB và chiết xuất nó để kiểm tra xem tiết kiệm là đúng.
Để loại bỏ những thay đổi được thực hiện để cơ sở dữ liệu trong @Test phương pháp tôi tái tạo cơ sở dữ liệu bằng cách JdbcTestUtils.executeSqlScript

+1

Thay vì sử dụng JdbcTestUtils, bạn có thể áp dụng chú thích @DirtiesContext. –

0

Bạn cũng nên chăm sóc của importedpackage: trong trường hợp của tôi, tôi nhập khẩu

nhập khẩu javax.transaction.Transactional;

thay vì

nhập khẩu org.springframework.transaction.annotation.Transactional;

1
  1. Có một cái nhìn here với cảnh báo về @Transactional kiểm tra (Spring Pitfalls: Transactional tests considered harmful). Tôi đã sử dụng @org.springframework.test.context.jdbc.Sql để điền lại DB trong các thử nghiệm dịch vụ của tôi và @Transactional cho bộ điều khiển.
  2. ConstraintViolationException để kiểm tra cập nhật bộ điều khiển với dữ liệu không hợp lệ đã được ném chỉ khi giao dịch được thực hiện. Vì vậy, tôi đã tìm thấy 3 tùy chọn:
    • 2.1 Kiểm tra chú thích với @Commit hoặc với @Transactional(propagation = Propagation.NEVER). Hãy nhận biết về sự thay đổi DB.
    • 2.2 Sử dụng TestTransaction

Code:

 TestTransaction.flagForCommit(); 
    TestTransaction.end(); 
  • 2,3 Sử dụng TransactionTemplate

Code:

@Autowired 
    private PlatformTransactionManager platformTransactionManager; 

    @Test(expected = Exception.class) 
    public void testUpdate() throws Exception { 
     TransactionTemplate transactionTemplate = new TransactionTemplate(platformTransactionManager); 
     transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); 
     String json = ... 
     transactionTemplate.execute(ts -> { 
      try { 
       mockMvc.perform(put(REST_URL + USER_ID) 
        .contentType(MediaType.APPLICATION_JSON) 
        .content(json)) 
        .andExpect(status().isOk()); 
       ... 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
      return null; 
     }); 
Các vấn đề liên quan