JUnit 4.x'te Suite yürütmeden önce ve sonra kanca


84

Testleri yürütmek için jUnit 4.4'ü kullanarak bir dizi entegrasyon testi için kurulumu önceden oluşturmaya ve sökmeye çalışıyorum. Sökmenin güvenilir bir şekilde çalıştırılması gerekir. TestNG ile ilgili başka sorunlar yaşıyorum, bu yüzden jUnit'e geri dönmek istiyorum. Herhangi bir test çalıştırılmadan önce ve tüm testler tamamlandıktan sonra yürütmek için hangi kancalar mevcuttur?

Not: Yapımız için maven 2 kullanıyoruz. Maven's pre-& phases'i kullanmayı denedim post-integration-test, ancak bir test başarısız olursa, maven durur ve çalışmaz post-integration-test, bu da yardımcı olmaz.


1
Entegrasyon testleri için surefire yerine maven-failsafe-eklentisini kullanmalısınız. Bu atlamak olmaz post-integration-testbir test başarısız olursa. Ayrıca bu wiki sayfasına bakın .
Chris H.

son uygulamayı paylaşır mısınız lütfen?
vikramvi

Yanıtlar:


114

Evet, bir test paketindeki herhangi bir testten önce ve sonra kurulum ve sökme yöntemlerini güvenilir bir şekilde çalıştırmak mümkündür. Kodla göstermeme izin verin:

package com.test;

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;

@RunWith(Suite.class)
@SuiteClasses({Test1.class, Test2.class})
public class TestSuite {

    @BeforeClass
    public static void setUp() {
        System.out.println("setting up");
    }

    @AfterClass
    public static void tearDown() {
        System.out.println("tearing down");
    }

}

Yani Test1sınıfınız şuna benzer:

package com.test;

import org.junit.Test;


public class Test1 {
    @Test
    public void test1() {
        System.out.println("test1");
    }

}

... ve bunun Test2benzer göründüğünü hayal edebilirsiniz . Koşarsan TestSuite, alırsın:

setting up
test1
test2
tearing down

Böylece kurulum / sökme işleminin yalnızca sırasıyla tüm testlerden önce ve sonra çalıştığını görebilirsiniz.

Yakalama: bu yalnızca test paketini çalıştırıyorsanız ve Test1 ve Test2'yi bağımsız JUnit testleri olarak çalıştırmıyorsanız işe yarar. Maven kullandığınızı söylediniz ve maven surefire eklentisi, testleri bir paketin parçası değil, ayrı ayrı çalıştırmayı seviyor. Bu durumda, her test sınıfının genişlettiği bir üst sınıf oluşturmanızı tavsiye ederim. Üst sınıf daha sonra açıklamalı @BeforeClass ve @AfterClass yöntemlerini içerir. Yukarıdaki yöntem kadar temiz olmasa da sizin için işe yarayacağını düşünüyorum.

Başarısız testlerle ilgili soruna gelince, maven.test.error.ignore ayarını yaparak başarısız testler üzerinde yapının devam etmesini sağlayabilirsiniz. Bu, sürekli bir uygulama olarak tavsiye edilmez, ancak tüm testleriniz geçene kadar çalışmanızı sağlamalıdır. Daha fazla ayrıntı için maven surefire belgelerine bakın .


2
Bu, maven-surefire-eklentisine girdiğimde ve çalıştırmak istediğim süite işaret eden bir listeyi oluşturduğumda mükemmel çalıştı.
Jherico

2
JUnit 4.8.2'den itibaren, bu, parametreli testlerle iyi oynamıyor. Suite'in @BeforeClass yöntemleri, Testin @ Parameterized.Parameters yönteminden sonra çalıştırılacak ve Suite'in kurulumuna herhangi bir bağımlılığı önleyecektir.
Anm

Kendime yanıt olarak, @ Theories kullanırken @DataPoints yöntemine yapılan çağrı, Suite'in @BeforeClass öğesinden sonra çağrılır.
Anm

19
Necro için üzgünüm - ancak bir süper sınıfa BeforeClass / AfterClass eklemek beklendiği gibi çalışmıyor - yine de her test sınıfı tamamlandıktan sonra çağrılıyorlar. Bu gelecek nesiller içindir.
Subu Sankara Subramanian

3
Bu hala geçerli bir yaklaşım mı? SuiteClasses açıklamasında test sınıfları listesini sıralama ihtiyacından nasıl kurtulursunuz?
Burhan Ali

34

Bir meslektaşım şunu önerdi: özel bir RunListener kullanabilir ve testRunFinished () yöntemini uygulayabilirsiniz: http://junit.sourceforge.net/javadoc/org/junit/runner/notification/RunListener.html#testRunFinished(org. junit.runner.Result)

RunListener'ı kaydetmek için surefire eklentisini aşağıdaki gibi yapılandırmanız yeterlidir: http://maven.apache.org/surefire/maven-surefire-plugin/examples/junit.html "Özel dinleyicileri ve muhabirleri kullanma" bölümü

Bu konfigürasyon aynı zamanda hatasız eklenti tarafından seçilmelidir. Bu çözüm harika çünkü Takımları, arama testi sınıflarını veya bunlardan herhangi birini belirtmek zorunda değilsiniz - Maven'in sihrini yapmasını ve tüm testlerin bitmesini beklemesini sağlar.


5
+1 Bu, Suites sınıfının zahmetli bakımı olmadan gördüğüm ilk kullanılabilir çözüm!
Stefan Haberl


6

Ek açıklamaları kullanarak şöyle bir şey yapabilirsiniz:

import org.junit.*;
import static org.junit.Assert.*;
import java.util.*;

class SomethingUnitTest {
    @BeforeClass
    public static void runBeforeClass()
    {

    }

    @AfterClass
    public static void runAfterClass()
    {  

    }

    @Before  
    public void setUp()
    {

    }

    @After
    public void tearDown()
    {

    }

    @Test
    public void testSomethingOrOther()
    {

    }

}

4
Kurulum ve sökme işleminin her çalıştırmada bir kez yürütülmesi gerekir. Bu, yalnızca tüm testlerin tek bir sınıfta olması durumunda yardımcı olacaktır.
sblundy

Bu, tüm test adımını değil, yalnızca bireysel test paketini kurar
Ben

3

Burada biz

  • JUnit 4.5'e yükseltildi,
  • Çalışan bir hizmet gerektiren her test sınıfını veya yöntemi etiketlemek için açıklamalar yazdı,
  • hizmetin kurulumunu ve sökülmesini uygulamak için statik yöntemler içeren her ek açıklama için işleyiciler yazdı,
  • Statik işleyici yöntemlerini uygun noktalardaki test yürütme zincirine ekleyerek testler üzerindeki ek açıklamaları bulmak için olağan Runner'ı genişletti.

2

"Not: Derlememiz için maven 2 kullanıyoruz. Maven'in entegrasyon öncesi ve sonrası test aşamalarını kullanmayı denedim, ancak bir test başarısız olursa, maven durur ve entegrasyon testini çalıştırmaz , ki bu yardımcı olmaz. "

bunun yerine güvenli eklentiyi deneyebilirsiniz, bence kurulum veya ara aşama durumuna bakılmaksızın temizliğin yapılmasını sağlayacak tesise sahip


Evet, hataya dayanıklı eklenti, belirli bir kurulum ve sökme belirlemenize izin verir. Bu sorunun yayınlandığı sırada güvenli olmadığını düşünmeme rağmen.
Jason Axelson

2

Tüm testlerinizin "teknik" bir sınıfı genişletmesi ve aynı pakette olması koşuluyla, küçük bir numara yapabilirsiniz:

public class AbstractTest {
  private static int nbTests = listClassesIn(<package>).size();
  private static int curTest = 0;

  @BeforeClass
  public static void incCurTest() { curTest++; }

  @AfterClass
  public static void closeTestSuite() {
      if (curTest == nbTests) { /*cleaning*/ }             
  }
}

public class Test1 extends AbstractTest {
   @Test
   public void check() {}
}
public class Test2 extends AbstractTest {
   @Test
   public void check() {}
}

Bu çözümün birçok dezavantajı olduğunu unutmayın:

  • paketin tüm testlerini yürütmeli
  • bir "techincal" sınıfını alt sınıflandırmalıdır
  • alt sınıfların içinde @BeforeClass ve @AfterClass kullanamazsınız
  • pakette yalnızca bir test yaparsanız, temizlik yapılmaz
  • ...

Bilgi için: listClassesIn () => Java'da belirli bir sınıfın tüm alt sınıflarını nasıl bulursunuz?


1
kendi testlerimin gösterdiği kadarıyla bu doğru değil. Sınıftan önce gömülü cam balığı başlatan ve dersten sonra kapatan süper bir sınıfım var. O süper sınıftan çıkan 2 sınıfım var. Önceki sınıf, her sınıfta tanımlanan testleri çalıştırmadan önce çalıştırılır.
Jonathan Morales Vélez

0

Bildiğim kadarıyla JUnit'te bunu yapmak için bir mekanizma yok, ancak Suite'i alt sınıflara ayırmayı ve run () yöntemini kanca sağlayan bir sürümle geçersiz kılmayı deneyebilirsiniz.


0

Maven-surefire-plugin önce Suite sınıfını çalıştırmadığından, paket ve test sınıflarını aynı şekilde ele aldığından, eklentiyi yalnızca süit sınıflarını etkinleştirmek ve tüm testleri devre dışı bırakmak için aşağıdaki gibi yapılandırabiliriz. Suite tüm testleri çalıştıracak.

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.5</version>
            <configuration>
                <includes>
                    <include>**/*Suite.java</include>
                </includes>
                <excludes>
                    <exclude>**/*Test.java</exclude>
                    <exclude>**/*Tests.java</exclude>
                </excludes>
            </configuration>
        </plugin>

0

O zaman, istediğiniz işlevselliği elde etmenin tek yolu şunun gibi bir şey yapmak olacaktır:

import junit.framework.Test;  
import junit.framework.TestResult;  
import junit.framework.TestSuite;  

public class AllTests {  
    public static Test suite() {  
        TestSuite suite = new TestSuite("TestEverything");  
        //$JUnit-BEGIN$  
        suite.addTestSuite(TestOne.class);  
        suite.addTestSuite(TestTwo.class);  
        suite.addTestSuite(TestThree.class);  
        //$JUnit-END$  
     }  

     public static void main(String[] args)  
     {  
        AllTests test = new AllTests();  
        Test testCase = test.suite();  
        TestResult result = new TestResult();  
        setUp();  
        testCase.run(result);  
        tearDown();  
     }  
     public void setUp() {}  
     public void tearDown() {}  
} 

Tutulma sırasında buna benzer bir şey kullanıyorum, bu yüzden bu ortamın dışında ne kadar taşınabilir olduğundan emin değilim


3
Bu, JUnit3 için bir örnektir ve OP, JUnit4'ü istedi, ancak bazı JUnit3 kullanıcılarının bu soruyu bulması durumunda ... JUnit3 için main () yönteminden kurtulup suite () yöntemine sahip olmak daha iyi olacaktır. TestSuite'i junit.extensions.TestSetup alt sınıfına sarın. Yine de Julie'nin IDE'nizde bireysel test sınıflarını çalıştırma örneğiyle aynı uyarılara sahipsiniz.
NamshubWriter

0

Bir paket oluşturmak istemiyorsanız ve tüm test sınıflarınızı listelemeniz gerekiyorsa, test sınıflarının sayısını dinamik olarak bulmak için yansımayı kullanabilir ve tearDown'u yalnızca bir kez yapmak için @AfterClass temel sınıfında geri sayım yapabilirsiniz:

public class BaseTestClass
{
    private static int testClassToRun = 0;

    // Counting the classes to run so that we can do the tear down only once
    static {
        try {
            Field field = ClassLoader.class.getDeclaredField("classes");
            field.setAccessible(true);

            @SuppressWarnings({ "unchecked", "rawtypes" })
            Vector<Class> classes = (Vector<Class>) field.get(BlockJUnit4ClassRunner.class.getClassLoader());
            for (Class<?> clazz : classes) {
                if (clazz.getName().endsWith("Test")) {
                    testClassToRun++;
                }
            }
        } catch (Exception ignore) {
        }
    }

    // Setup that needs to be done only once
    static {
        // one time set up
    }

    @AfterClass
    public static void baseTearDown() throws Exception
    {
        if (--testClassToRun == 0) {
            // one time clean up
        }
    }
}

Statik bloklar yerine @BeforeClass kullanmayı tercih ederseniz, yansıma sayımı yapmak ve kurulumu ilk çağrıda yalnızca bir kez test etmek için bir boole bayrağı da kullanabilirsiniz. Umarım bu birine yardımcı olur, bir süitteki tüm dersleri saymaktan daha iyi bir yol bulmam bir öğleden sonrayı aldı.

Şimdi yapmanız gereken tek şey, bu sınıfı tüm test sınıflarınız için genişletmek. Tüm testlerimiz için bazı ortak şeyler sağlamak için zaten bir temel sınıfımız vardı, bu yüzden bu bizim için en iyi çözümdü.

İlham bu SO cevabından geliyor https://stackoverflow.com/a/37488620/5930242

Bu sınıfı her yere genişletmek istemiyorsanız, bu son SO cevabı istediğinizi yapabilir.

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.