次の Spring MVC アプリ スタックがあります。
コントローラ -> サービス -> DAO (リポジトリ) -> エンティティ -> MySql InnoDB
トランザクションは、AOP xml 構成を使用してサービス層から開始するように構成されており、アプリは完全に機能します。
<aop:config>
<aop:advisor id="managerTx" advice-ref="txAdvice" pointcut="execution(* *..service.*Service.*(..))" order="1"/>
</aop:config>
<aop:aspectj-autoproxy proxy-target-class="true"/>
<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
現在、spring-mvc-test フレームワーク、UnitDB などを使用して Spring MVC テストを作成しています。テスト クラスには次の構成があります。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
loader=WebContextLoader.class,
locations={
"classpath:spring/testContext.xml",
"classpath:spring/testDispatcher-servlet.xml",
"classpath:spring/security.xml"
})
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class,
DbUnitTestExecutionListener.class })
@TransactionConfiguration(transactionManager="transactionManager", defaultRollback=true)
@Transactional(propagation=Propagation.REQUIRED, rollbackFor={Exception.class})
@DatabaseSetup({"classpath:dbunit/initial-data.xml"})
テストは次のようになります。
@Test
public void testSomeController() throws Exception {
this.mockMvc.perform(get("/some/controller"));
}
基本的に、テスト環境内で既存の Spring AOP 構成をテスト (使用) し、最初にいくつかの DB データをセットアップし、テストを実行し、テストが完了したらすべてをロールバックします。
上記の構成では、テストは独自のトランザクションを開始しています。指定された伝播構成では、AOP xml 構成によって開始されたサービス層で別のトランザクションに遭遇しています。テストによって開始されたトランザクションがによって開始されたトランザクションを待っているため、ロック タイムアウト エラーが発生します。サービス層での AOP 構成。
私はテストを書いているだけで、実際のコードを変更するのではなく、テスト コードのみを変更する必要があります。私の仕事は、指定された構成でテストによって行われたすべての変更をロールバックする方法を見つけることです。
どんなアイデアでも大歓迎です。
編集
問題となるケースは次のとおりです。
- test クラスは、すべてのテストに対して自動ロールバックを使用して 1 つの大きな新しいトランザクションを開始します。
- dbunit はデータベースに初期データを入力します
- test はコントローラのテストを起動します
- コントローラーは、エンティティの保存/更新などのサービス レイヤーを呼び出します (テスト クラスの先頭で DBUnit によって挿入されます)。ここでサービス レイヤーで新しいトランザクションが開始されます (aop:config によって構成されます) が、ステップ #1 からの大きなトランザクションでサポートされます
- ブーム、エラーが発生: ロック待機タイムアウトを超えました。トランザクションを再開してみてください
DBUnit で挿入されたデータは、同じトランザクション内にあるため、まだコミットされていないと思います。別のトランザクションで DBUnit を使用して初期データを挿入する方法を見つける必要がありますが、テストの最後にロールバックします。