Junit - kurulum yöntemini bir kez çalıştır


Yanıtlar:


205

@Assylias'a, kullanmanın @BeforeClassklasik bir çözüm olduğu konusunda hemfikir olsam da her zaman uygun değildir. Açıklanan yöntem @BeforeClassstatik olmalıdır. Test senaryosu örneğine ihtiyaç duyan bazı testler için çok sakıncalıdır. Örneğin @Autowired, yay bağlamında tanımlanan hizmetlerle çalışmak için kullanılan Yay tabanlı testler .

Bu durumda, kişisel olarak setUp()açıklama eklenmiş normal yöntemi kullanıyorum @Beforeve özel static(!) booleanBayrağımı yönetiyorum :

private static boolean setUpIsDone = false;
.....
@Before
public void setUp() {
    if (setUpIsDone) {
        return;
    }
    // do the setup
    setUpIsDone = true;
}

10
Kenny Cason'un neden durağan olması gerektiğiyle ilgili yorumuna ek olarak. JUnit, her @Test yöntemi için test sınıfının yeni bir örneğini oluşturduğundan statik olmalıdır. Örnek değişkeni, statik değilse, her örnek için varsayılan değerine (yanlış) sıfırlanacaktır. Daha fazla bilgi için bakın: martinfowler.com/bliki/JunitNewInstance.html
dustin.schultz

2
Bu, setUp()yöntemin bir üst sınıfta olduğu durum dışında çalışır - bu sorunu çözmek için aşağıda bir yanıt gönderdik .
Steve Chambers

4
Bunu 84k temsilcisi olan birine söylemekten çekiniyorum, ancak BeforeClass aslında şu soruyu yanıtlamıyor: BeforeClass her test sınıfının başında çalıştırılır. Ancak OP, "tüm testlerden önce yalnızca bir kez" çalışan birini istedi. Önerilen çözümünüz bunu yapabilir, ancak tüm test sınıflarınızın bir "CommonTest" sınıfını genişletmesini sağlamalısınız ...
mike rodent

1
@mikerodent, IMHO OP kendi test senaryosundaki tüm testleri sordu, genel olarak tüm testleri değil. Yani yorumunuz daha az alakalı. BTW, itibarı yüksek olsa bile hiç kimseye bir şey söylemekten çekinme. En azından benim yaptığım bu :). Ve Ağustos 2012'de soruyu yanıtladığımda itibarım önemli ölçüde azaldı.
AlexR

Benim durumum için işe yaramıyor, kurulumda başlatılan değişkenler her testten sonra sıfırlanıyor, bu yüzden yalnızca bir kez başlatmak anlamsız.
Aphax

89

Sen kullanabilirsiniz ek açıklama :BeforeClass

@BeforeClass
public static void setUpClass() {
    //executed only once, before the first test
}

12
Bunu kullanamam, getClass ()
Bober02

1
@ Bober02 BeforeClass'ın gerçekten statik olması gerekiyor. Bunu kullanamazsanız, diğer cevap bir geçici çözüm sağlar.
assylias

2
TheClassYouWant.classGetClass () çağrınız yerine kullanamayacağınızdan emin misiniz ? Bu gerçek bir Java geçerli: String.class.getName().
stolsvik


1
@mikerodent Soruyu "sınıftaki tüm testler" olarak anladım - ama haklısınız, OP'nin istediği şey olmayabilir.
asylias

29

JUnit 5 artık @BeforeAll ek açıklamasına sahip:

Açıklamalı yöntemin, geçerli sınıf veya sınıf hiyerarşisindeki tüm @Test yöntemlerinden önce yürütülmesi gerektiğini belirtir; JUnit 4'ün @BeforeClass'a benzer. Bu tür yöntemler statik olmalıdır.

JUnit 5'in yaşam döngüsü ek açıklamaları sonunda doğru yapmış gibi görünüyor! Bakmadan bile hangi ek açıklamaların mevcut olduğunu tahmin edebilirsiniz (örneğin @BeforeEach @AfterAll)


6
Aynı sorunu var @BeforeClass, olması gerekiyordu static. IMO @ AlexR'nin çözümü daha güzel.
zengr

@zengr sizinle aynı fikirde: AlexR'ye söylediğim gibi, çözümü, yalnızca bir kez çalıştırılacaksa, tüm test sınıflarının bir CommonTest sınıfından alt sınıfa girmesini gerektirir. Ancak, olabildiğince basit ve IMHO, dilde basit bir mekanizma mevcut olduğunda muhtemelen "süslü" bir çerçeve tarafından sağlanan çözümü kullanmamalısınız. Tabii ki iyi bir sebep olmadıkça. Ayrıca, onun gibi basit bir şeyi iyi bir "kutunun üzerinde yazdığı şeyi yapar" tip adıyla kullanmak okunabilirliğe yardımcı olur.
mike kemirgen

Bunu söyledim, yine IMHO, bir "AfterAll" ek açıklamasına sahip olmak için çok daha fazla gerekçe var gibi görünüyor: tüm testlerin ne zaman yapıldığını tespit etmek için bir mekanizma tasarlamak çok zor ve uydurma olurdu. Tersine, elbette, safçılar muhtemelen asla "son bir temizlik" yapmamanız gerektiğini, yani her "tearDown" un tüm kaynakları bozulmamış durumda bırakması gerektiğini söyleyeceklerdir ... ve muhtemelen haklıdırlar!
mike kemirgen

Bu, her biri kendi testlerine sahip birden çok modülün bulunduğu Maven ile çalışıyor mu?
Mark Boon

@mike rodent, benim durumumda, dosya sistemindeki test dosyalarını her testten önce / sonra kurmak ve yırtmak dosyalarda kilitlenmelere yol açıyor gibi görünüyor. Şimdilik, AlexR'nin bir kez kurma çözümüne bağımsız olarak ulaştım. İki statik bayrağım var, zatenKuruluş ve kirli. setup (), başlangıçta bir kirli durum algılanırsa veya bir kurulum hatası kirli bir duruma yol açarsa cleanup () öğesini çağırır. Testleri çalıştırdıktan sonra temizlemek için onları tekrar çalıştırıyorum. Dağınık, hiç de ideal değil, inşa sürecimizde değil. Hala daha iyi bir yol arıyor (jUnit 4.12).
Rebeccah

9

Ne zaman setUp()bir test sınıfın bir üst sınıfta (örneğin AbstractTestBaseaşağıdaki gibi altı) kabul cevap değiştirilebilir:

public abstract class AbstractTestBase {
    private static Class<? extends AbstractTestBase> testClass;
    .....
    public void setUp() {
        if (this.getClass().equals(testClass)) {
            return;
        }

        // do the setup - once per concrete test class
        .....
        testClass = this.getClass();
    }
}

Bu, statik olmayan tek bir setUp()yöntem için çalışmalı, ancak tearDown()karmaşık bir yansıma dünyasına girmeden bir eşdeğer üretemiyorum ... Ödül yapabilen herkese işaret ediyor!


3

Düzenleme: Hata ayıklarken, sınıfın da her testten önce başlatıldığını öğrendim. Sanırım @BeforeClass ek açıklaması burada en iyisi.

Sen de yapıcı kurabilirsiniz, test sınıf olan bir sınıf sonuçta. Bunun kötü bir uygulama olup olmadığından emin değilim çünkü neredeyse tüm diğer yöntemler açıklanmış durumda, ama işe yarıyor. Bunun gibi bir kurucu oluşturabilirsiniz:

public UT () {
    // initialize once here
}
@Test
// Some test here...

Ctor, statik olmadıkları için testlerden önce çağrılacaktır.


0

Bu çözümü deneyin: https://stackoverflow.com/a/46274919/907576 :

@BeforeAllMethods/ @AfterAllMethodsannotation ile , tüm enjekte edilen değerlerin mevcut olduğu bir örnek bağlamında Test sınıfındaki herhangi bir yöntemi çalıştırabilirsiniz.


Üçüncü taraf bir kitaplığa dayanır.
Andrew

0

Kirli çözümüm:

public class TestCaseExtended extends TestCase {

    private boolean isInitialized = false;
    private int serId;

    @Override
    public void setUp() throws Exception {
        super.setUp();
        if(!isInitialized) {
            loadSaveNewSerId();
            emptyTestResultsDirectory();
            isInitialized = true;
        }
    }

   ...

}

Bunu tüm test durumlarım için temel olarak kullanıyorum.


public class TestCaseExtended TestCase'i genişletir {private static boolean isInitialized = false; özel statik TestCaseExtended caseExtended; özel int serId; @Override public void setUp (), Exception {super.setUp () atar; eğer (! isInitialized) {caseExtended = new TestCaseExtended (); caseExtended.loadSaveNewSerId (); caseExtended.emptyTestResultsDirectory (); isInitialized = true; }}
Obi Two

0

Her alt testte ayarlanmış ve kontrol edilmiş bir değişkenin bildirimini zorlamak istemiyorsanız, bunu bir SuperTest'e eklemek şunları yapabilir:

public abstract class SuperTest {

    private static final ConcurrentHashMap<Class, Boolean> INITIALIZED = new ConcurrentHashMap<>();
    protected final boolean initialized() {
        final boolean[] absent = {false};
        INITIALIZED.computeIfAbsent(this.getClass(), (klass)-> {
            return absent[0] = true;
        });
        return !absent[0];
    }
}



public class SubTest extends SuperTest {
    @Before
    public void before() {
        if ( super.initialized() ) return;

         ... magic ... 
    }

}

0

Bu sorunu şu şekilde çözdüm:

Senin ekleyin Taban soyut sınıfı (daki sürücüsünü başlatmak Acımasız soyut sınıf setUpDriver () bu kod parçası yöntemi):

private static boolean started = false;
static{
    if (!started) {
        started = true;
        try {
            setUpDriver();  //method where you initialize your driver
        } catch (MalformedURLException e) {
        }
    }
}

Ve şimdi, test sınıflarınız Base soyut sınıftan genişleyecekse -> setUpDriver () yöntemi ilk @Test'ten önce çalıştırma başına yalnızca BİR kez çalıştırılacaktır.


0

Tüm başlatma işlerini yapmak için Spring'in @PostConstruct yöntemini kullanın ve bu yöntem herhangi bir @ Test yürütülmeden önce çalışır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.