2016-05-24 77 views
2

我正在使用Spring Boot 1.4.0.M3。當@Commit使用@Transactional時,無法測試預期的異常

我有,有一個username這應該是唯一的@Entity

@NotNull 
@Column(unique = true) 
@Pattern(regexp = "[a-zA-Z_\\-\\.0-9]+") 
@Size(min = 1, max = 30) 
private String username; 

使用彈簧數據儲存庫,我想測試是否會有一個異常時,使用重複的用戶名。這個測試工作:

@SpringBootTest 
@RunWith(SpringRunner.class) 
public class UserRepositoryIntegrationTest { 

    @Autowired 
    private UserRepository repository; 

    @Test(expected = DataIntegrityViolationException.class) 
    public void test() { 
     repository.save(User.createAdmin(repository.nextId(), "wim", "123456")); 
     repository.save(User.createAdmin(repository.nextId(), "wim", "123456")); 
    } 
} 

然而,增加@Transactional@Commit時,測試失敗:

@SpringBootTest 
@RunWith(SpringRunner.class) 
@Transactional 
public class UserRepositoryIntegrationTest { 

    @Autowired 
    private UserRepository repository; 

    @Test(expected = DataIntegrityViolationException.class) 
    @Commit 
    public void test() { 
     repository.save(User.createAdmin(repository.nextId(), "wim", "123456")); 
     repository.save(User.createAdmin(repository.nextId(), "wim", "123456")); 
    } 
} 

但看日誌,該DataIntegrityViolationException被拋出:

2016-05-24 09:05:16.619 ERROR 22790 --- [ main] o.h.engine.jdbc.spi.SqlExceptionHelper : Unique index or primary key violation: "UK_D8HGQ87BS4VPMC81NQ9G69G8X_INDEX_D ON PUBLIC.MYPROJECT_USER(USERNAME) VALUES ('wim', 1)"; SQL statement: insert into myproject_user (password, username, role, id) values (?, ?, 'ADMIN', ?) [23505-191] 2016-05-24 09:05:16.620 INFO 22790 --- [
main] o.h.e.j.b.internal.AbstractBatchImpl : HHH000010: On release of batch it still contained JDBC statements 2016-05-24 09:05:16.629 WARN 22790 --- [ main] o.s.test.context.TestContextManager
: Caught exception while allowing TestExecutionListener [org.springframew[email protected]589b3632] to process 'after' execution for test: method [public void com.spring.boot.test.user.UserRepositoryIntegrationTest.test()], instance [[email protected]], exception [java.lang.AssertionError: Expected exception: org.springframework.dao.DataIntegrityViolationException]

爲什麼測試失敗了嗎?難道JUnit會在Spring提交事務之前檢查異常是否被拋出?

+1

這是預期... AFTER事務提交會發生的異常。該方法結束後,事務提交。所以在檢查時基本上沒有例外。你用這個改變了測試的行爲。你需要在你的方法中提交。 –

+1

「允許TestExecutionListener引發異常」說了這一切。你想提交但你想斷言提交失敗。 JUnit和Spring沒有意識到對方,所以你不能使用JUnit斷言來處理那些東西。正如Martin所說的,在測試中使用'TestTransaction#end'。 –

+0

感謝您指點該班。不知道它存在。我已經添加了完整的工作版本的答案。 –

回答

2

基於由M.Deinum和斯蒂芬·尼科爾的意見,這是工作版本:

@SpringBootTest 
@RunWith(SpringRunner.class) 
@Transactional 
public class UserRepositoryIntegrationTest { 

    @Autowired 
    private UserRepository repository; 

    @Test(expected = DataIntegrityViolationException.class) 
    public void test() { 
     repository.save(User.createAdmin(repository.nextId(), "wim", "123456")); 
     repository.save(User.createAdmin(repository.nextId(), "wim", "123456")); 

     TestTransaction.flagForCommit(); 
     TestTransaction.end(); 
    } 
} 

需要注意的是靜態方法需要被調用,使其工作。

+0

偉大的你讓我的一天,這是一個完美的答案,簡短而甜美 –

2

您不需要提交。您只需將您的工作單元刷新到數據庫以便查看DataIntegrityViolationException

這在Spring Reference Manual中描述。向下滾動到「誤報」的註釋。但請注意,必須通過@PersistenceContext(而不是@Autowired)注入EntityManager

下應該可以正常工作對您:

@RunWith(SpringRunner.class) 
@SpringBootTest 
@Transactional 
public class UserRepositoryIntegrationTest { 

    @Autowired 
    UserRepository repository; 

    @PersistenceContext 
    EntityManager entityManager; 

    @Test(expected = DataIntegrityViolationException.class) 
    public void test() { 
     repository.save(User.createAdmin(repository.nextId(), "wim", "123456")); 
     repository.save(User.createAdmin(repository.nextId(), "wim", "123456")); 

     entityManager.flush(); 
    } 
} 

問候,

山姆(的筆者闡述了Spring TestContext框架

1

我需要測試在MVC控制器測試DataIntegrityViolationException@WebAppConfiguration),並在內部應用做@ResponseStatus修改。所以你的方法不適合我,它太晚了。不幸的是在Spring 4中排除了@NotTransactional註解,所以我只是將我的測試分開爲@Transactional而不是事務性的。另請參閱http://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/testing.html#integration-testing-annotations from

@NotTransactional is deprecated

UPDATE。 2種方式解決:

  • 單獨測試明確的事務性和非事務性
  • 使用@Transactional(propagation = Propagation.NEVER)此時事務是不可取的
+0

這不是問題的答案。您可以將此添加爲對答案的評論,或者詢問提及此問題的單獨問題。 –

+0

是的,我同意你的意見。但對於與您的問題相同的人來說,這是一個很好的選擇。 – GKislin

相關問題