Aynı Junit testini defalarca çalıştırmanın kolay yolu?


123

Başlığın dediği gibi, JUnit 4.x testlerini Eclipse kullanarak arka arkaya birkaç kez çalıştırmanın basit bir yolunu arıyorum.

Bir örnek, aynı testi arka arkaya 10 kez çalıştırıp sonucu geri bildirmek olabilir.

Bunu yapmanın karmaşık bir yolunu zaten bulduk, ancak bunu yapmanın basit bir yolunu arıyorum, böylece düzeltmeye çalıştığım lapa lapa testin sabit kalacağından emin olabilirim.

İdeal bir çözüm, farkında olmadığım bir Eclipse eklentisi / ayarı / özelliği olabilir.


5
Bunu neden yapmak isteyeceğini çok merak ediyorum.
Buhb

Büyük bir kara kutu testi yapıyorum, küçük bir değişiklik yaptım ve bunun daha önce başarısız olan bu testin kararlılığını nasıl etkilediğini görmek istiyorum.
Stefan Thyberg

Gerçekten, başarısız olana kadar çalışmasını istemeniz dışında, ben sadece birkaç kez çalıştırmak istiyorum, bu da aldığım yanıtları etkileyebilir.
Stefan Thyberg

4
TestNG'ye karşı mısınız, çünkü öyle değilse @Test'i (invocationCount = 10) kullanabilirsiniz ve hepsi bu kadar.
Robert Massaioli

1
TestNG'ye "karşı" değildim, sadece onu o projede kullanmıyorduk.
Stefan Thyberg

Yanıtlar:


123

Bunu yapmanın en kolay (en az miktarda yeni kod gerektiği gibi) yolu, testi parametreleştirilmiş bir test olarak çalıştırmaktır ( @RunWith(Parameterized.class)10 boş parametre sağlamak için bir ile açıklama ekleyin ve bir yöntem ekleyin). Bu şekilde, çerçeve testi 10 kez çalıştıracaktır.

Bu testin sınıftaki tek test olması veya daha iyisi tüm test yöntemlerinin sınıfta 10 kez çalıştırılması gerekir.

İşte bir örnek:

@RunWith(Parameterized.class)
public class RunTenTimes {

    @Parameterized.Parameters
    public static Object[][] data() {
        return new Object[10][0];
    }

    public RunTenTimes() {
    }

    @Test
    public void runsTenTimes() {
        System.out.println("run");
    }
}

Yukarıdakilerle, bunu parametresiz bir kurucu ile yapmak bile mümkündür, ancak çerçeve yazarlarının bunu amaçladığından veya gelecekte bunun bozulup bozulmayacağından emin değilim.

Kendi koşucunuzu uyguluyorsanız, koşucunun testi 10 kez çalıştırmasını sağlayabilirsiniz. Üçüncü taraf bir çalıştırıcı kullanıyorsanız, 4.7 ile, yeni @Ruleaçıklamayı kullanabilir ve MethodRulearayüzü uygulayabilir, böylece ifadeyi alır ve bir for döngüsünde 10 kez çalıştırır. Bu yaklaşımın geçerli dezavantajı olduğunu @Beforeve @Aftersadece bir kez çalıştırmak olsun. Bu muhtemelen JUnit'in bir sonraki sürümünde değişecektir ( @Beforebundan sonra çalışacaktır @Rule), ancak ne olursa olsun nesnenin aynı örneği üzerinde hareket edeceksiniz ( Parameterizedkoşucu için geçerli olmayan bir şey ). Bu, sınıfı birlikte çalıştırdığınız koşucunun @Ruleek açıklamaları doğru şekilde tanıdığını varsayar . Bu sadece JUnit koşucularına yetki veriyorsa geçerlidir.

@RuleEk açıklamayı tanımayan özel bir koşucu ile koşuyorsanız, o Koşucuya uygun şekilde yetki veren ve onu 10 kez çalıştıran kendi koşucunuzu yazmak zorunda kalırsınız.

Bunu potansiyel olarak çözmenin başka yolları da olduğunu unutmayın (Teoriler koşucusu gibi), ancak hepsinin bir koşucu gerektirdiğini unutmayın. Maalesef JUnit şu anda koşucu katmanlarını desteklemiyor. Bu diğer koşucuları zincirleyen bir koşucu.


2
Maalesef başka bir koşucuyla @RunWith'i zaten çalıştırıyorum, ancak aksi takdirde bu ideal bir çözüm olurdu.
Stefan Thyberg

Evet, yine de sahip olmak istediğim çözüm bu ve çoğu insan için en iyisi olacak, bu yüzden devam edip yanıtı kabul edeceğim.
Stefan Thyberg

Alternatif ve muhtemelen daha az karmaşık bir çözüm için bkz .: stackoverflow.com/a/21349010/281545
Mr_and_Mrs_D

Güzel çözüm! Veri yönteminin Yinelenebilir Arrays döndürmesi gerektiğini söyleyen bir istisna var. Buna göre düzelttim: @ Parameterized.Parameters public static Yinelenebilir <Object []> data () {return Arrays.asList (new Object [20] [0]); }
nadre

1
JUnit 5 için bu yanıta bağlantı verebilir misiniz ? JUnit 5
Marcono1234

102

IntelliJ ile bunu test yapılandırmasından yapabilirsiniz. Bu pencereyi açtığınızda, testi istediğiniz sayıda çalıştırmayı seçebilirsiniz.

görüntü açıklamasını buraya girin

testi çalıştırdığınızda, intellij, seçtiğiniz tüm testleri belirttiğiniz sayıda yürütecektir.

624 testi 10 kez çalıştıran örnek: görüntü açıklamasını buraya girin


4
Bu mükemmel, şimdi bunu yapmanın tutulma yoluna işaret edebilirseniz, bu OP'nin sorusuna şu noktaya kadar cevap verecektir
Khal

Gerçek mantığı veya gereksinimleri barındırmak için belirli bir araca güvenmek bir anti-modeldir.
Mickael

1
@Mickael Bir testi N kez tekrarlamak genellikle test için bir gereklilik değildir. Aslında testler deterministik olmalıdır, böylece kaç kez tekrarlanırsa tekrarlansın, her zaman aynı sonucu vermelidir. Bahsettiğiniz anti kalıbı açıklayabilir misiniz?
smac89

Bir testin tekrarlanması 1 geliştirici için faydalı olduysa, muhtemelen diğerleri için faydalı olacaktır. Bu nedenle, test çalışma zamanı ve kod, tekrarı etkinleştirmek için mantığı barındırabiliyorsa, çabayı ve çözümü çarpanlara ayırmaya ve katkıda bulunanların aracı aynı sonuçla istediği şekilde kullanmalarına izin verdiği için tercih edilmelidir. IDE / geliştirici alanına yeniden kullanılabilir mantığı koda konulduğunda koymak, bir çeşit çarpanlara ayırma eksikliğidir.
Mickael

68

Spring'in tekrar eden açıklamasının bu tür şeyler için yararlı olduğunu buldum:

@Repeat(value = 10)

En son (Spring Framework 4.3.11.RELEASE API) belgesi:


46
Test çerçevelerini değiştirmek, bunu yapmanın kolay bir yolu olarak adlandırdığım bir şey değil.
Stefan Thyberg

3
Test çerçevenizi değiştirmenize gerek yok - JUnit ile sorunsuz çalışıyor. Ana dezavantaj, JUnit'in bunu hala tek bir test olarak görmesidir. Yani ilk kırıldığında infaz duracak. Ancak, Spring'i halihazırda kullanmıyorsanız, muhtemelen gitmek istediğiniz yol bu değildir ...
54'te tveon

Benim için işe yaramıyor gibi görünüyor (Spring Boot 1.5.1 üzerinden Spring 4.3.6)
David Tonhofer

İlkbahar botu 2.1.6 ve Junit 5
jo

Yaylı önyükleme ile mükemmel çalışır 2. Posterin 'ilkbaharda birim testi' bağlantısına göre @RunWith (SpringRunner :: class) eklemeyi unutmayın!
Agoston Horvath

33

Aşağıdaki kaynaklardan esinlenilmiştir:

Misal

Aşağıdaki @Repeatgibi bir ek açıklama oluşturun ve kullanın :

public class MyTestClass {

    @Rule
    public RepeatRule repeatRule = new RepeatRule();

    @Test
    @Repeat(10)
    public void testMyCode() {
        //your test code goes here
    }
}

Repeat.java

import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.METHOD;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention( RetentionPolicy.RUNTIME )
@Target({ METHOD, ANNOTATION_TYPE })
public @interface Repeat {
    int value() default 1;
}

RepeatRule.java

import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;

public class RepeatRule implements TestRule {

    private static class RepeatStatement extends Statement {
        private final Statement statement;
        private final int repeat;    

        public RepeatStatement(Statement statement, int repeat) {
            this.statement = statement;
            this.repeat = repeat;
        }

        @Override
        public void evaluate() throws Throwable {
            for (int i = 0; i < repeat; i++) {
                statement.evaluate();
            }
        }

    }

    @Override
    public Statement apply(Statement statement, Description description) {
        Statement result = statement;
        Repeat repeat = description.getAnnotation(Repeat.class);
        if (repeat != null) {
            int times = repeat.value();
            result = new RepeatStatement(statement, times);
        }
        return result;
    }
}

PowerMock

Bu çözümü ile kullanmak @RunWith(PowerMockRunner.class), Powermock 1.6.5'e ( bir yama içeren ) güncelleme gerektirir .


Evet. Testleri nasıl yapıyorsunuz?
R. Oosterholt

Tutulmayı kendim kullanmıyorum. Belki bir Junut 4 test koşucusu kullanmıyorsunuz? ( "Bir Test Yapılandırmasını Özelleştirme" belgesine bakın )
R. Oosterholt

29

JUnit 5 ile @RepeatedTest ek açıklamasını kullanarak bunu çözebildim :

@RepeatedTest(10)
public void testMyCode() {
    //your test code goes here
}

@TestEk açıklamanın birlikte kullanılmaması gerektiğini unutmayın @RepeatedTest.


Henüz yayınlanmış bir sürüm olmadığını unutmamak için çok umut verici görünüyor.
9ilsdx 9rvj 0lo

1
JUnit 5, birkaç hafta önce GA'yı vurdu.
mkobit

11

Herhangi bir sorun var:

@Test
void itWorks() {
    // stuff
}

@Test
void itWorksRepeatably() {
    for (int i = 0; i < 10; i++) {
        itWorks();
    }
}

Bir dizi değerin her birini test ettiğiniz durumun aksine, hangi çalışmanın başarısız olduğunu özellikle umursamıyorsunuz.

Kodda yapabileceklerinizi yapılandırmada veya açıklamada yapmaya gerek yok.


2
Normal birim testleri olarak birkaç test çalıştırmak ve her biri için bir izleme ve durum elde etmek istiyorum.
Stefan Thyberg 01

24
Bu durumda "@Before" ve "@After" ler çalıştırılmayacak
Bogdan

3
Bu, sorunumu @Beforeçözmeden önce açıklamalı yöntemi manuel olarak çağırmakla birlikte itWorks().
João Neves

KURU konseptini biliyor musunuz? en.wikipedia.org/wiki/Don%27t_repeat_yourself Döngünüzü her yere kopyalayıp yapıştırmak yerine bazı kurulumlar yapmanızı öneririm.
Kikiwa

Bu yanıt için düzenleme sırası dolu; bu nedenle, bunu bir yoruma ekleyeceğim: JUnit4 için testlerin halka açık olması gerekir.
Richard Jessop

7

Bu benim için çok daha kolay çalışıyor.

public class RepeatTests extends TestCase {

    public static Test suite() {
        TestSuite suite = new TestSuite(RepeatTests.class.getName());

        for (int i = 0; i < 10; i++) {              
        suite.addTestSuite(YourTest.class);             
        }

        return suite;
    }
}

Başka bir çerçeve kullanmadığı için harika ve aslında JUnit 3 ile çalışıyor (android için çok önemli)
Vladimir Ivanov

1
JUnit4 ile bir uygulama Runner ile yapılabilir: public class RepeatRunner extends BlockJUnit4ClassRunner { public RepeatRunner(Class klass) throws InitializationError { super(klass); } @Override public void run(final RunNotifier notifier) { for (int i = 0; i < 10; i++) { super.run(notifier); } } }En azından Eclipse JUnit eklentisinde şu gibi sonuçlar almanıza rağmen: "10/1 test geçti"
Peter Wippermann

7

Tempus-fugit kitaplığında, JUnit 4.7'ler ile @Rulebir testi birkaç kez veya bununla tekrarlamak için çalışan Aralıklı bir açıklama vardır @RunWith.

Örneğin,

@RunWith(IntermittentTestRunner.class)
public class IntermittentTestRunnerTest {

   private static int testCounter = 0;

   @Test
   @Intermittent(repition = 99)
   public void annotatedTest() {
      testCounter++;
   }
}

Test çalıştırıldıktan sonra (içinde IntermittentTestRunner ile @RunWith) testCounter99'a eşit olacaktır.


Evet, burada da aynı problem, zaten başka bir koşucu kullanıyor ve bu yüzden bunu kullanamıyorum, yine de iyi fikir.
Stefan Thyberg

Evet, RunWith ile aynı sorunu yaşıyorum ... devam ederken tempus-fugit'i biraz aşmak için ayarladım, tekrar tekrar koşmak istediğinizde koşucu yerine @ Kural kullanabilirsiniz. Aralıklı yerine @Repeating ile işaretliyorsunuz. Kural versiyonu @ Before / @ Afters olsa da çalışmaz. Daha fazla ayrıntı için tempus-fugit.googlecode.com/svn/site/documentation/… sayfasına bakın (test yüklemek / bekletmek için aşağı kaydırın).
Toby

0

Bu tür testlerin yapılmasına izin veren bir modül oluşturuyorum. Ancak sadece tekrara odaklanmaz. Ancak bazı kod parçalarının İş Parçacığı için güvenli olduğunu garanti altına alır.

https://github.com/anderson-marques/concurrent-testing

Maven bağımlılığı:

<dependency>
    <groupId>org.lite</groupId>
    <artifactId>concurrent-testing</artifactId>
    <version>1.0.0</version>
</dependency>

Kullanım örneği:

package org.lite.concurrent.testing;

import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import ConcurrentTest;
import ConcurrentTestsRule;

/**
 * Concurrent tests examples
 */
public class ExampleTest {

    /**
     * Create a new TestRule that will be applied to all tests
     */
    @Rule
    public ConcurrentTestsRule ct = ConcurrentTestsRule.silentTests();

    /**
     * Tests using 10 threads and make 20 requests. This means until 10 simultaneous requests.
     */
    @Test
    @ConcurrentTest(requests = 20, threads = 10)
    public void testConcurrentExecutionSuccess(){
        Assert.assertTrue(true);
    }

    /**
     * Tests using 10 threads and make 20 requests. This means until 10 simultaneous requests.
     */
    @Test
    @ConcurrentTest(requests = 200, threads = 10, timeoutMillis = 100)
    public void testConcurrentExecutionSuccessWaitOnly100Millissecond(){
    }

    @Test(expected = RuntimeException.class)
    @ConcurrentTest(requests = 3)
    public void testConcurrentExecutionFail(){
        throw new RuntimeException("Fail");
    }
}

Bu açık kaynak kodlu bir projedir. Kendinizi geliştirmekten çekinmeyin.


0

JUnit testinizi bir ana yöntemden çalıştırabilir ve ihtiyacınız olan birçok kez tekrarlayabilirsiniz:

package tests;

import static org.junit.Assert.*;

import org.junit.Test;
import org.junit.runner.Result;

public class RepeatedTest {

    @Test
    public void test() {
        fail("Not yet implemented");
    }

    public static void main(String args[]) {

        boolean runForever = true;

        while (runForever) {
            Result result = org.junit.runner.JUnitCore.runClasses(RepeatedTest.class);

            if (result.getFailureCount() > 0) {
                runForever = false;
               //Do something with the result object

            }
        }

    }

}

0

Bu, aslında Yishai'nin Kotlin'de yeniden yazdığı yukarıda verilen cevaptır:

@RunWith(Parameterized::class)
class MyTest {

    companion object {

        private const val numberOfTests = 200

        @JvmStatic
        @Parameterized.Parameters
        fun data(): Array<Array<Any?>> = Array(numberOfTests) { arrayOfNulls<Any?>(0) }
    }

    @Test
    fun testSomething() { }
}
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.