2016-04-10 68 views
2

Ben @TransactionalEvents mevcut Bahar JUnit Testleri ile (@TransactionalTestExecutionListener veya altsınıflamayla AbstractTransactionalUnit4SpringContextTests ya aracılığıyla çalıştırın (Bahar 4.2 https://spring.io/blog/2015/02/11/better-application-events-in-spring-framework-4-2 bir özellik) test etmek çalışıyordum ama, zorunlu bir seçenek var gibi görünüyor - - ya bir @Rollback şerhe testi veya olaylar ateş etmeyin testleri @Rollback mümkün olurken kimse @TransactionalEvents test etmek için iyi bir şekilde karşımıza HasTest @TransactionalEvents ve @Rollback

+0

:-) bir cazibe gibi çalışır Bu şekilde işlemeye çağrılacak sen, sen Bunu farklı bir şekilde test ediyorum. Çerçeveyi kendi kodunuzdan ziyade test edebileceğinizi iddia ediyorum. –

+0

Kabul ettiğimden emin değilim, ama biraz düşüneceğim. @Rollback, ilk test durumuna geri dönmek için veritabanını sıfırlamaktır (testlerin birbiriyle etkileşime girme ihtimalinin daha az olduğundan emin olmak için). – adam

+0

Ne yaptığını biliyorum. Sorun şu ki, işlemin gerçekleştiği bir olayı soruyorsunuz. Olmadı. –

cevap

3

Stéphane Nicoll doğrudur: TransactionPhase için eğer.? Sizin @TransactionalEventListener, AFTER_COMMIT olarak ayarlanmış, daha sonra otomatik rollback semantiği ile bir işlem testi olması hiçbir zaman bir anlam ifade etmemektedir çünkü olay asla ateş etti. Başka bir deyişle

, o işlem tamamlanmış asla eğer bir işlem tamamlanmış sonra ateş bir olay için hiçbir yolu yoktur.

Bu nedenle, etkinliğin gerçekten yapılmasını istiyorsanız, işlemin gerçekleştirilmesine izin vermeniz gerekir (ör., Test yönteminizi @Commit ile ekleyerek). tamamlamak sonra temizlemek için, işlem işlediği sonra temizleme komut dosyalarını yürütmek için izole modunda @Sql kullanmak gerekir. Örneğin, aşağıdaki (denenmemiş kodu) gibi bir şey sizin için işe yarayabilecek:

@Transactional 
@Commit 
@Sql(scripts = "/cleanup.sql", executionPhase = AFTER_TEST_METHOD, 
    config = @SqlConfig(transactionMode = TransactionMode.ISOLATED)) 
@Test 
public void test() { /* ... */ } 

Saygılarımızla,

Sam

+0

Tamam, teşekkürler. Bu şekilde çalışmış olduğum gibi, benim yanlış anlaşılmamın bir kısmı, yayılmadan bağımsız olarak \ @Transactional çağrıların, en yüksek \ @ Transactional yöntemi tamamlanana kadar Olayı beklemeye devam etmesidir. – adam

1

Sam Brannen en solüsyonu (Bahar TestContext Çerçeve ait yazarı) neredeyse ile çalışır Adam'ın yorumuyla ilgili. Test yöntemi, işlem tamamlanmış sonra

Aslında @TransactionalEventListener ile açıklanmış yöntemler olarak adlandırılır. Bunun nedeni, olayı gündeme getiren çağrı yönteminin, fiziksel değil, mantıksal bir işlem içinde yürütülmesidir. Bunun yerine, çağrı yöntemi yeni bir fiziksel işlem içinde yürütüldüğünde, @TransactionalEventListener ile açıklamalı olan yöntemler, örneğin, test yöntemi işlemi gerçekleştirilmeden önce doğru zamanda çağrılır. biz aslında bu işlemlerin umurumda değil çünkü

Ayrıca, test yöntemleri @Commit gerekmez. Ancak, çağrı yönteminin taahhüt edilen değişikliklerini geri almak için Sam Brannen tarafından açıklandığı gibi @Sql(...) ifadesine ihtiyacımız var.

aşağıda küçük örneğe bakın. işlem tamamlanmış olduğunda (@TransactionalEventListener varsayılan davranış) denir dinleyici

İlk:

@Component 
public class MyListener { 

    @TransactionalEventListener 
    public void when(MyEvent event) { 
     ... 
    } 
} 

Sonra olayı yayınlayan uygulama hizmeti yukarıda sınıfı tarafından dinledi.Sam Brannen tarafından değil değil @Commit şerhe önerdiği gibi

@Service 
@Transactional(propagation = Propagation.REQUIRES_NEW) 
public class MyApplicationService { 

    public void doSomething() { 
     // ... 
     // publishes an instance of MyEvent 
     // ... 
    } 
} 
Nihayet

test yöntemi: işlemler yöntem çağrılır her zaman (daha fazla ayrıntı için Spring Framework doc bakınız) yeni fiziksel olanlar olmak üzere yapılandırılmıştır dikkat edin Bu noktada gerekli: Eğer test kullandığı işlem geri ve kod emin belli bir parça olmak için

@Transactional 
@Sql(scripts = "/cleanup.sql", executionPhase = AFTER_TEST_METHOD, 
    config = @SqlConfig(transactionMode = TransactionMode.ISOLATED)) 
@Test 
public void test() { 
    MyApplicationService target = // ... 
    target.doSomething(); 
    // the event is now received by MyListener 
    // assertions on the side effects of MyListener 
    // ... 
} 

o