Wiele instrukcji RunWith w jUnit


113

Piszę testy jednostkowe i chcę używać JUnitParamsRunneri MockitoJUnitRunnerdla jednej klasy testowej.

Niestety nie działa:

@RunWith(MockitoJUnitRunner.class)
@RunWith(JUnitParamsRunner.class)
public class DatabaseModelTest {
  // some tests
}

Czy istnieje sposób na użycie obu, Mockito i JUnitParams w jednej klasie testowej?



2
Jest tu również fajny przykład: blog.project13.pl/index.php/coding/1077/…
— falsarella

Odpowiedzi:


110

Nie możesz tego zrobić, ponieważ zgodnie ze specyfikacją nie możesz umieścić tej samej adnotacji dwa razy na tym samym elemencie z adnotacją.

Więc jakie jest rozwiązanie? Rozwiązaniem jest postawienie tylko jednego @RunWith()z biegaczem, bez którego nie można się obejść i zastąpienie drugiego czymś innym. W twoim przypadku myślę, że usuniesz MockitoJUnitRunneri zrobisz programowo to, co robi.

Właściwie jedyne, co robi, to działa:

MockitoAnnotations.initMocks(test);

na początku przypadku testowego. Zatem najprostszym rozwiązaniem jest umieszczenie tego kodu w setUp()metodzie:

@Before
public void setUp() {
    MockitoAnnotations.initMocks(this);
}

Nie jestem pewien, ale prawdopodobnie powinieneś unikać wielokrotnego wywoływania tej metody za pomocą flagi:

private boolean mockInitialized = false;
@Before
public void setUp() {
    if (!mockInitialized) {
        MockitoAnnotations.initMocks(this);
        mockInitialized = true;  
    }
}

Jednak lepsze rozwiązanie wielokrotnego użytku można wdrożyć zgodnie z regułami JUnt.

public class MockitoRule extends TestWatcher {
    private boolean mockInitialized = false;

    @Override
    protected void starting(Description d) {
        if (!mockInitialized) {
            MockitoAnnotations.initMocks(this);
            mockInitialized = true;  
        }
    }
}

Teraz po prostu dodaj następujący wiersz do swojej klasy testowej:

@Rule public MockitoRule mockitoRule = MockitoJUnit.rule();

i możesz uruchomić ten przypadek testowy z dowolnym biegaczem.


12
Czek mockInitializedjest zły. Chcesz mieć świeżą próbę na każdy test.
— BetaRide

1
@BetaRide, to zależy od Twoich potrzeb. Czasami chcesz za każdym razem zainicjować mock, czasami nie.
— AlexR

Jeśli chcesz skonfigurować tylko raz na plik klasy, możesz użyć BeforeClass zamiast Before, które zostanie wywołane raz i tylko raz na plik testowy.
— InfernalRapture,

56

Począwszy od JUnit 4.7 i Mockito 1.10.17, ta funkcja jest wbudowana; jest org.mockito.junit.MockitoRuleklasa. Możesz go po prostu zaimportować i dodać linię

@Rule public MockitoRule mockitoRule = MockitoJUnit.rule();

do klasy testowej.


2
W przypadku starszych wersji Mockito (do 1.10.5 wydaje się), musisz użyć:@Rule public MockitoJUnitRule mockito = new MockitoJUnitRule(this);
— Cliff Sun

MockitoAnnotations.initMocks(this)bardzo wolno tworzy kpiny. Najbardziej wydajnym sposobem jest użycie @Runwith (MockitoJunitRunner.class)
— ant2009

16

To rozwiązanie działa dla każdego możliwego biegacza, nie tylko ten przykład mockito. Na przykład; na wiosnę po prostu zmień klasy biegaczy i dodaj niezbędne adnotacje.

@RunWith(JUnitParamsRunner.class)
public class DatabaseModelTest {

    @Test
    public void subRunner() throws Exception {
        JUnitCore.runClasses(TestMockitoJUnitRunner.class);
    }

    @RunWith(MockitoJUnitRunner.class)
    public static class TestMockitoJUnitRunner {
    }
}

DatabaseModelTestbędzie prowadzony przez JUnit. TestMockitoJUnitRunnerzależy od tego (zgodnie z logiką) i zostanie uruchomione wewnątrz metody main w @Testmetodzie podczas wywołania JUnitCore.runClasses(TestMockitoJUnitRunner.class). Ta metoda zapewnia, że ​​główny profil jest uruchamiany poprawnie przedstatic class TestMockitoJUnitRunner pomocniczego, skutecznie implementując wiele zagnieżdżonych @RunWithadnotacji z zależnymi klasami testowymi.

Również na https://bekce.github.io/junit-multiple-runwith-dependent-tests


3
Dzwoniąc JUnitCore.runClasses()bez sprawdzenia wyniku, ryzykujesz zamaskowanie błędów z testu wewnętrznego. assert(JUnitCore.runClasses(TestMockitoJUnitRunner.class).wasSuccessful());przynajmniej zgłosi błąd
— Robotnik


2

W moim przypadku próbowałem Kpić z jakiejś metody w wiosennej fasoli i

MockitoAnnotations.initMocks(test);

nie działa. Zamiast tego musisz zdefiniować ten bean do konstruowania przy użyciu metody mock w pliku xml, jak poniżej.

...
<bean id="classWantedToBeMocked" class="org.mockito.Mockito" factory-method="mock">
    <constructor-arg value="com.fullpath.ClassWantedToBeMocked" />
</bean>
...

i dodaj tę fasolę z autowiredem w klasie testowej, jak naśladowanie.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="file:springconfig.xml")
public class TestClass {
    ...
    @Autowired
    private ClassWantedToBeMocked classWantedToBeMocked;
    ...
    when(classWantedToBeMocked.methodWantedToBeMocked()).thenReturn(...);
    ...
}

0

sprawdź ten link https://bekce.github.io/junit-multiple-runwith-dependent-tests/ stosując to podejście połączyłem @RunWith (Parameterized.class) - biegacz zewnętrzny - z @RunWith (MockitoJUnitRunner.class) - biegacz wewnętrzny. Jedyną poprawką, jaką musiałem dodać, było uczynienie moich zmiennych składowych w zewnętrznej klasie / runner statyczne, aby były dostępne dla wewnętrznej / zagnieżdżonej runner / klasy. mam szczęście i ciesz się.


0

Chciałem uruchomić SWTBotJunit4ClassRunner i org.junit.runners.Parametryzowane w tym samym czasie, mam testy parametryczne i chcę zrzuty ekranu, gdy test SWT się nie powiedzie (funkcję zrzutu ekranu zapewnia SWTBotJunit4ClassRunner ). Odpowiedź @ bekce jest świetna i najpierw chciałem iść tą drogą, ale albo było dziwaczne, gdy przechodziło przez argumenty. Lub zrobienie parametryzacji w podklasie i utrata informacji, jakie dokładnie testy przeszły / nie powiodły się i mają tylko ostatni zrzut ekranu (ponieważ nazwy zrzutów ekranu otrzymują nazwę z samego testu). Tak czy inaczej było trochę niechlujnie.

W moim przypadku SWTBotJunit4ClassRunner jest dość prosty, więc sklonowałem kod źródłowy klasy, nadałem mu własną nazwę ParametrizedScreenshotRunner i tam, gdzie oryginał rozszerzał TestRunner , moja klasa rozszerzyła parametr Parameterized klasę więc w zasadzie mogę użyć własnego runnera zamiast dwóch poprzednich. Podsumowując, mój własny runner rozszerza się na Sparametryzowany biegacz, jednocześnie implementując funkcję zrzutu ekranu, teraz mój test używa tego „hybrydowego” biegacza i wszystkie testy działają zgodnie z oczekiwaniami od razu (nie ma potrzeby niczego zmieniać w testach).

Tak to wygląda (ze względu na zwięzłość usunąłem wszystkie komentarze z aukcji):

package mySwtTests;

import org.junit.runners.Parameterized;
import org.eclipse.swtbot.swt.finder.junit.ScreenshotCaptureListener;
import org.junit.runner.notification.RunListener;
import org.junit.runner.notification.RunNotifier;

public class ParametrizedScreenshotRunner extends TestRu Parameterized {

    public ParametrizedScreenshotRunner(Class<?> klass) throws Throwable {
        super(klass);
    }

    public void run(RunNotifier notifier) {
        RunListener failureSpy = new ScreenshotCaptureListener();
        notifier.removeListener(failureSpy); // remove existing listeners that could be added by suite or class runners
        notifier.addListener(failureSpy);
        try {
            super.run(notifier);
        } finally {
            notifier.removeListener(failureSpy);
        }
    }
}

-15

Możesz też spróbować tego:

@RunWith(JUnitParamsRunner.class)
public class AbstractTestClass {
  // some tests
}

@RunWith(MockitoJUnitRunner.class)
public class DatabaseModelTest extends AbstractTestClass {
  // some tests
}

2
To nie zadziała, tylko adnotacja podklasy zostanie przetworzona.
— PaulNUK

nie działa - tylko adnotacja MockitoJUnitRunner będzie brana pod uwagę
— Przemek Bielicki
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.