Giao dịch khôi phục sau @Test


85

Trước hết, tôi đã tìm thấy rất nhiều chủ đề trên StackOverflow về vấn đề này, nhưng không ai trong số họ thực sự giúp được tôi, rất tiếc khi đặt câu hỏi có thể trùng lặp.

Tôi đang chạy các bài kiểm tra JUnit bằng Spring-test, mã của tôi trông như thế này

@RunWith(SpringJUnit4ClassRunner.class)  
@ContextConfiguration(locations = {})
public class StudentSystemTest {

    @Autowired
    private StudentSystem studentSystem;

    @Before
    public void initTest() {
    // set up the database, create basic structure for testing
    }

    @Test
    public void test1() {
    }    
    ...  
}

Vấn đề của tôi là tôi muốn các bài kiểm tra của mình KHÔNG ảnh hưởng đến các bài kiểm tra khác. Vì vậy, tôi muốn tạo một cái gì đó giống như khôi phục cho mỗi thử nghiệm. Tôi đã tìm kiếm rất nhiều cho điều này, nhưng tôi không tìm thấy gì cho đến nay. Tôi đang sử dụng Hibernate và MySql cho việc này


Ý bạn là gì khi quay lại ?. Làm sạch cơ sở dữ liệu?
Gaurav

5
đặt nó về trạng thái chính xác như sau khi thực thiinitTest
Jan Vorcak 27/09/12

Câu trả lời:


127

Chỉ cần thêm @Transactionalchú thích vào đầu bài kiểm tra của bạn:

@RunWith(SpringJUnit4ClassRunner.class)  
@ContextConfiguration(locations = {"testContext.xml"})
@Transactional
public class StudentSystemTest {

Theo mặc định, Spring sẽ bắt đầu một giao dịch mới xung quanh phương pháp thử nghiệm và @Before/ lệnh @Aftergọi lại của bạn, quay trở lại khi kết thúc. Nó hoạt động theo mặc định, đủ để có một số người quản lý giao dịch trong ngữ cảnh.

Từ: 10.3.5.4 Quản lý giao dịch (mỏ đậm):

Trong khung TestContext, các giao dịch được quản lý bởi TransactionalTestExecutionListener. Lưu ý rằng nó TransactionalTestExecutionListenerđược cấu hình theo mặc định , ngay cả khi bạn không khai báo rõ ràng @TestExecutionListenersvề lớp thử nghiệm của mình. Tuy nhiên, để kích hoạt hỗ trợ cho các giao dịch, bạn phải cung cấp một PlatformTransactionManagerbean trong ngữ cảnh ứng dụng được tải theo @ContextConfigurationngữ nghĩa. Ngoài ra, bạn phải khai báo @Transactionalở cấp lớp hoặc cấp phương pháp cho các bài kiểm tra của mình .


2
tốt, tôi đã thử điều này trước đây, và nó vẫn không hoạt động, có lẽ ... có thể vấn đề là tôi không xác định PlatformTransactionManager, làm thế nào tôi có thể làm điều đó?
Jan Vorcak

@javo: bạn đang sửa đổi cơ sở dữ liệu như thế nào? Nếu bạn đang sử dụng Jpa / Hibernate / JdbcTemplate / ... thì phải có một số PlatformTransactionManager. Nếu không, làm thế nào Spring sẽ biết về giao dịch và cơ sở dữ liệu của bạn?
Tomasz Nurkiewicz

1
Liên kết trong câu trả lời này không còn đúng nữa; xem câu trả lời của user2418306 bên dưới để biết liên kết chính xác và ngữ cảnh khác từ tài liệu Spring.
DaveyDaveDave

1
Tôi không làm việc, mỗi phương pháp đòi hỏi một giao dịch riêng biệt, không thể làm điều đó cho cả lớp
Kamil Nekanowicz

Tôi đang thử nghiệm chèn vào bảng. Với @Transactional, lệnh chèn thậm chí không được đưa ra đối với cơ sở dữ liệu (tôi có thể thấy điều đó vì bảng điều khiển có chế độ ngủ đông show-sql true). Hoạt động tốt trong nhiều trường hợp. Nhưng một trong những bài kiểm tra của tôi kiểm tra rằng cơ sở dữ liệu phát hành DataAccessException vì một ràng buộc cơ sở dữ liệu. Trong trường hợp này, kiểm tra không thành công vì quá trình khôi phục xảy ra "trong bộ nhớ" và cơ sở dữ liệu không bao giờ được gọi. Giải pháp: sử dụng @Transactional@Testcấp độ phương pháp chứ không phải ở cấp độ lớp học.
Paulo Merson

17

Ngoài ra: nỗ lực sửa đổi câu trả lời của Tomasz Nurkiewicz đã bị từ chối:

Chỉnh sửa này không làm cho bài đăng dễ đọc hơn, dễ tìm hơn, chính xác hơn hoặc dễ tiếp cận hơn một chút. Các thay đổi hoàn toàn không cần thiết hoặc có hại cho khả năng đọc.


Liên kết chính xác và vĩnh viễn đến phần liên quan của tài liệu về thử nghiệm tích hợp.

Để kích hoạt hỗ trợ cho các giao dịch, bạn phải cấu hình một PlatformTransactionManagerbean trong ApplicationContextđó được tải qua @ContextConfigurationngữ nghĩa.

@Cấu hình
@PropertySource ("application.properties")
Lớp công chúng Kiên trì {
    @ Không mong muốn
    Môi trường env;

    @Hạt đậu
    DataSource dataSource () {
        trả về DriverManagerDataSource mới (
                env.getProperty ("datasource.url"),
                env.getProperty ("datasource.user"),
                env.getProperty ("datasource.password")
        );
    }

    @Hạt đậu
    PlatformTransactionManager transactionManager () {
        trả về DataSourceTransactionManager mới (dataSource ());
    }
}

Ngoài ra, bạn phải khai báo @Transactionalchú thích của Spring ở cấp độ lớp hoặc phương thức cho các bài kiểm tra của mình.

@RunWith (SpringJUnit4ClassRunner.class)
@ContextConfiguration (các lớp = {Persistence.class, SomeRepository.class})
@Transactional
lớp công khai SomeRepositoryTest {...}

Chú thích một phương pháp thử nghiệm với các @Transactionalnguyên nhân chạy thử nghiệm trong một giao dịch, theo mặc định, sẽ được tự động quay lại sau khi hoàn thành thử nghiệm. Nếu một lớp thử nghiệm được chú thích bằng @Transactional, mỗi phương pháp thử nghiệm trong phân cấp lớp đó sẽ được chạy trong một giao dịch.


12

Các câu trả lời đề cập đến việc thêm @Transactionalđều đúng, nhưng để đơn giản hơn, bạn có thể có lớp thử nghiệm của mình extends AbstractTransactionalJUnit4SpringContextTests.


1
thêm chú thích '@Transactional' trên mức độ lớp không làm việc, thêm chú thích '@Transactional' riêng cho từng chức năng công trình, và mở rộng AbstractTransactionalJUnit4SpringContextTests công trình quá
Kamil Nekanowicz

5

Tôi biết, tôi đã quá muộn để đăng một câu trả lời, nhưng hy vọng rằng nó có thể giúp ích cho ai đó. Thêm vào đó, tôi vừa giải quyết được vấn đề này với các bài kiểm tra của mình. Đây là những gì tôi đã có trong bài kiểm tra của mình:

Lớp kiểm tra của tôi

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "path-to-context" })
@Transactional
public class MyIntegrationTest 

Xml ngữ cảnh

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
   <property name="driverClassName" value="${jdbc.driverClassName}" />
   <property name="url" value="${jdbc.url}" />
   <property name="username" value="${jdbc.username}" />
   <property name="password" value="${jdbc.password}" />
</bean>

Tôi vẫn gặp sự cố rằng, cơ sở dữ liệu không được dọn dẹp tự động.

Sự cố đã được giải quyết khi tôi thêm thuộc tính sau vào BasicDataSource

<property name="defaultAutoCommit" value="false" />

Hy vọng nó giúp.


Vậy bạn cam kết các báo cáo của mình theo cách thủ công? Bạn có chắc chắn dữ liệu của bạn thậm chí đã được ghi trong cơ sở dữ liệu của bạn?
crazya kocourek,

Đối với bất kỳ ai đang khó hiểu về Giao dịch mùa xuân, hãy đảm bảo rằng nguồn dữ liệu của bạn KHÔNG được đặt thành tự động cam kết, nếu không bạn sẽ khiến mình phát điên khi cố gắng tìm ra lý do tại sao @Transactional dường như không làm gì cả.
Joe Ernst

2

Bạn cần chạy thử nghiệm của mình với bối cảnh Spring và trình quản lý giao dịch, ví dụ:

@RunWith(SpringJUnit4ClassRunner.class)  
@ContextConfiguration(locations = {"/your-applicationContext.xml"})
@TransactionConfiguration(transactionManager="txMgr")
public class StudentSystemTest {

     @Test
     public void testTransactionalService() {
         // test transactional service
     }

     @Test
     @Transactional
     public void testNonTransactionalService() {
         // test non-transactional service
     }
}

Xem chương 3.5.8. Transaction Managementcủa Spring tham khảo để biết thêm chi tiết.



-4

Bạn có thể vô hiệu hóa Rollback:

@TransactionConfiguration(defaultRollback = false)

Thí dụ:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@Transactional
@TransactionConfiguration(defaultRollback = false)
public class Test {
    @PersistenceContext
    private EntityManager em;

    @org.junit.Test
    public void menge() {
        PersistentObject object = new PersistentObject();
        em.persist(object);
        em.flush();
    }
}

6
Đó là hoàn toàn ngược lại những gì mà OP là yêu cầu cho
Adam Michalik

Đây đáng lẽ phải là một bình luận cho câu trả lời được chấp nhận.
DerMike
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.