ย้อนกลับธุรกรรมหลังจาก @Test


86

ก่อนอื่นฉันพบเธรดจำนวนมากใน StackOverflow เกี่ยวกับเรื่องนี้ แต่ไม่มีสิ่งใดที่ช่วยฉันได้จริงๆขอโทษที่ถามคำถามที่อาจซ้ำกัน

ฉันกำลังทำการทดสอบ JUnit โดยใช้การทดสอบสปริงโค้ดของฉันมีลักษณะเช่นนี้

@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() {
    }    
    ...  
}

ปัญหาของฉันคือฉันต้องการให้การทดสอบของฉันไม่มีผลต่อการทดสอบอื่น ๆ ดังนั้นฉันต้องการสร้างบางสิ่งเช่นย้อนกลับสำหรับการทดสอบแต่ละครั้ง ฉันค้นหาสิ่งนี้มามากมาย แต่ฉันไม่พบอะไรเลย ฉันใช้ Hibernate และ MySql สำหรับสิ่งนี้


คุณหมายถึงอะไรโดยการย้อนกลับ?. ทำความสะอาดฐานข้อมูล?
Gaurav

5
ตั้งค่าให้อยู่ในสถานะเดียวกันทุกinitTest
ประการ

คำตอบ:


129

เพียงเพิ่ม@Transactionalคำอธิบายประกอบที่ด้านบนของการทดสอบของคุณ:

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

ตามค่าเริ่มต้น Spring จะเริ่มธุรกรรมใหม่โดยใช้วิธีทดสอบและ@Before/ การ@Afterเรียกกลับของคุณโดยย้อนกลับไปในตอนท้าย มันทำงานตามค่าเริ่มต้นก็เพียงพอที่จะมีตัวจัดการธุรกรรมบางอย่างในบริบท

จาก: 10.3.5.4 การจัดการธุรกรรม (ตัวหนาของฉัน):

ในกรอบงาน TestContext ธุรกรรมถูกจัดการโดย TransactionalTestExecutionListener โปรดทราบว่าTransactionalTestExecutionListenerมีการกำหนดค่าตามค่าเริ่มต้นแม้ว่าคุณจะไม่ได้ประกาศอย่างชัดเจน@TestExecutionListenersในคลาสทดสอบของคุณก็ตาม อย่างไรก็ตามในการเปิดใช้งานการสนับสนุนสำหรับธุรกรรมคุณต้องจัดเตรียมPlatformTransactionManagerbean ในบริบทของแอ็พพลิเคชันที่โหลดโดย@ContextConfigurationความหมาย นอกจากนี้คุณจะต้องประกาศ@Transactionalทั้งในชั้นเรียนหรือวิธีการสำหรับการทดสอบระดับของคุณ


2
ฉันลองทำก่อนหน้านี้แล้ว แต่ก็ยังไม่ได้ผลบางที ... ปัญหาอาจเกิดจากฉันไม่ได้กำหนด PlatformTransactionManager ฉันจะทำอย่างไร
ม.ค. Vorcak

@javo: คุณแก้ไขฐานข้อมูลอย่างไร? หากคุณกำลังใช้ Jpa / Hibernate / JdbcTemplate / ... PlatformTransactionManagerต้องมีบาง มิฉะนั้น Spring จะรู้เกี่ยวกับธุรกรรมและฐานข้อมูลของคุณได้อย่างไร?
Tomasz Nurkiewicz

1
ลิงก์ในคำตอบนี้ไม่ถูกต้องอีกต่อไป ดูคำตอบของ user2418306 ด้านล่างสำหรับลิงก์ที่ถูกต้องและบริบทเพิ่มเติมจากเอกสาร Spring
DaveyDaveDave

1
ฉันไม่ได้ทำงานแต่ละวิธีต้องใช้ธุรกรรมแยกกันไม่สามารถทำได้สำหรับทั้งชั้นเรียน
Kamil Nekanowicz

ฉันกำลังทดสอบการแทรกในตาราง ด้วย @Transactional คำสั่ง insert จะไม่ออกมาเทียบกับฐานข้อมูลด้วยซ้ำ (ฉันเห็นได้ว่าเนื่องจากคอนโซลมี hibernate show-sql true) ใช้ได้ดีในหลาย ๆ กรณี แต่หนึ่งในการทดสอบของฉันตรวจสอบว่าฐานข้อมูลออก DataAccessException เนื่องจากข้อ จำกัด ของฐานข้อมูล ในกรณีนี้การทดสอบล้มเหลวเนื่องจากการย้อนกลับเกิดขึ้น "ในหน่วยความจำ" และไม่มีการเรียกฐานข้อมูล วิธีแก้ไข: ใช้@Transactionalใน@Testระดับวิธีการไม่ใช่ในระดับชั้นเรียน
Paulo Merson

17

นอกเหนือ:ความพยายามที่จะแก้ไขคำตอบของ Tomasz Nurkiewicz ถูกปฏิเสธ:

การแก้ไขนี้ไม่ได้ทำให้โพสต์อ่านง่ายขึ้นค้นหาง่ายขึ้นถูกต้องมากขึ้นหรือเข้าถึงได้มากขึ้น การเปลี่ยนแปลงอาจไม่จำเป็นโดยสิ้นเชิงหรือเป็นอันตรายต่อความสามารถในการอ่าน


ลิงก์ที่ถูกต้องและถาวรไปยังส่วนที่เกี่ยวข้องของเอกสารเกี่ยวกับการทดสอบการรวมระบบ

ในการเปิดใช้งานการสนับสนุนสำหรับธุรกรรมคุณต้องกำหนดค่าPlatformTransactionManagerbean ในApplicationContextที่โหลดผ่านทาง@ContextConfigurationความหมาย

@ คอนเฟริม
@PropertySource ("application.properties")
ความคงอยู่ของชนชั้นสาธารณะ {
    @ อัตโนมัติ
    สภาพแวดล้อม env;

    @ถั่ว
    แหล่งข้อมูล dataSource () {
        ส่งคืน DriverManagerDataSource ใหม่ (
                env.getProperty ("datasource.url"),
                env.getProperty ("datasource.user"),
                env.getProperty ("datasource.password")
        );
    }

    @ถั่ว
    PlatformTransactionManager transactionManager () {
        ส่งคืน DataSourceTransactionManager ใหม่ (dataSource ());
    }
}

นอกจากนี้คุณต้องประกาศ@Transactionalคำอธิบายประกอบของ Spring ในระดับชั้นเรียนหรือระดับวิธีการสำหรับการทดสอบของคุณ

@RunWith (SpringJUnit4ClassRunner.class)
@ContextConfiguration (คลาส = {Persistence.class, SomeRepository.class})
@ การทำธุรกรรม
คลาสสาธารณะ SomeRepositoryTest {... }

การใส่คำอธิบายประกอบวิธีการทดสอบที่@Transactionalทำให้การทดสอบถูกเรียกใช้ภายในธุรกรรมซึ่งโดยค่าเริ่มต้นจะย้อนกลับโดยอัตโนมัติหลังจากเสร็จสิ้นการทดสอบ หากคลาสทดสอบถูกใส่คำอธิบายประกอบ@Transactionalวิธีการทดสอบแต่ละรายการภายในลำดับชั้นของคลาสนั้นจะถูกเรียกใช้ภายในธุรกรรม


12

คำตอบที่กล่าวถึงการเพิ่ม@Transactionalนั้นถูกต้อง แต่เพื่อความง่ายคุณสามารถมีคลาสทดสอบของคุณextends AbstractTransactionalJUnit4SpringContextTestsได้


1
การเพิ่มคำอธิบายประกอบ '@Transactional' ในระดับชั้นเรียนไม่ทำงานการเพิ่มคำอธิบายประกอบ '@Transactional' แยกกันสำหรับแต่ละฟังก์ชันและขยาย AbstractTransactionalJUnit4SpringContextTests ก็ใช้ได้เช่นกัน
Kamil Nekanowicz

5

ฉันรู้ว่าฉันโพสต์คำตอบช้าเกินไป แต่หวังว่ามันจะช่วยใครสักคนได้ นอกจากนี้ฉันเพิ่งแก้ไขปัญหานี้ที่ฉันมีกับการทดสอบของฉัน นี่คือสิ่งที่ฉันมีในการทดสอบของฉัน:

ชั้นทดสอบของฉัน

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

บริบท xml

<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>

ฉันยังคงมีปัญหาที่ฐานข้อมูลไม่ได้รับการทำความสะอาดโดยอัตโนมัติ

ปัญหาได้รับการแก้ไขเมื่อฉันเพิ่มคุณสมบัติต่อไปนี้ใน BasicDataSource

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

หวังว่าจะช่วยได้


ดังนั้นคุณยอมรับงบของคุณด้วยตนเอง? คุณแน่ใจหรือไม่ว่าข้อมูลของคุณถูกเขียนไว้ในฐานข้อมูลของคุณ
franta kocourek

สำหรับใครก็ตามที่พยายามทำความเข้าใจ Spring Transactions ตรวจสอบให้แน่ใจว่าแหล่งข้อมูลของคุณไม่ได้ถูกตั้งค่าให้ทำการคอมมิตอัตโนมัติมิฉะนั้นคุณจะต้องพยายามหาเหตุผลว่าทำไม @Transactional จึงดูเหมือนจะไม่ทำอะไรเลย
Joe Ernst

2

คุณต้องดำเนินการทดสอบของคุณด้วยบริบท Spring และตัวจัดการธุรกรรมเช่น

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

ดูบท3.5.8. Transaction Managementอ้างอิง Spring สำหรับรายละเอียดเพิ่มเติม


0

นอกเหนือจากการเพิ่ม@Transactionalใน@Testวิธีการที่คุณยังต้องเพิ่ม@Rollback(false)


-5

คุณสามารถปิดการย้อนกลับได้:

@TransactionConfiguration(defaultRollback = false)

ตัวอย่าง:

@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
นั่นตรงข้ามกับสิ่งที่ OP ต้องการ
Adam Michalik

นี่ควรเป็นความคิดเห็นของคำตอบที่ยอมรับ
DerMike
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.