Несколько выражений RunWith в jUnit


113

Я пишу модульный тест и хочу использовать JUnitParamsRunnerи MockitoJUnitRunnerдля одного тестового класса.

К сожалению, не работает следующее:

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

Есть ли способ использовать и Mockito, и JUnitParams в одном тестовом классе?



2
Здесь также есть хороший пример: blog.project13.pl/index.php/coding/1077/…
— falsarella

Ответы:


110

Вы не можете этого сделать, потому что в соответствии со спецификацией вы не можете дважды поместить одну и ту же аннотацию на один и тот же аннотированный элемент.

Итак, какое решение? Решение состоит в том, чтобы поставить только один @RunWith()бегунок, без которого вы не можете стоять, и заменить другой на что-то другое. В вашем случае, я думаю, вы удалите MockitoJUnitRunnerи сделаете программно то, что он делает.

Фактически единственное, что он делает, это запускает:

MockitoAnnotations.initMocks(test);

в начале тестового примера. Итак, самое простое решение - поместить этот код в setUp()метод:

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

Я не уверен, но, вероятно, вам следует избегать многократного вызова этого метода с использованием флага:

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

Однако лучше многоразовое решение может быть реализовано с помощью правил JUnt.

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

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

Теперь просто добавьте следующую строку в свой тестовый класс:

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

и вы можете запустить этот тестовый пример с любым бегуном.


13
Проверка mockInitializedневерна. Вы хотите иметь свежий макет для каждого тетста.
— BetaRide

1
@BetaRide, это зависит от ваших потребностей. Иногда вы хотите инициализировать mock каждый раз, иногда нет.
— AlexR

Если вы хотите настроить один раз для каждого файла класса, вы можете использовать BeforeClass вместо Before, которая будет вызываться один раз и только один раз для каждого тестового файла.
— InfernalRapture

56

Начиная с JUnit 4.7 и Mockito 1.10.17, эта функциональность встроена; есть org.mockito.junit.MockitoRuleкласс. Вы можете просто импортировать его и добавить строку

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

в свой тестовый класс.


2
Для более старых версий Mockito (кажется, до 1.10.5) вы должны использовать:@Rule public MockitoJUnitRule mockito = new MockitoJUnitRule(this);
— Cliff Sun

MockitoAnnotations.initMocks(this)очень медленно создает макеты. Самый эффективный способ - использовать @Runwith (MockitoJunitRunner.class)
— ant2009 02

16

Это решение работает для всех возможных бегунов, а не только для этого примера mockito. Например; для Spring просто измените классы бегунов и добавьте необходимые аннотации.

@RunWith(JUnitParamsRunner.class)
public class DatabaseModelTest {

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

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

DatabaseModelTestбудет выполняться JUnit. TestMockitoJUnitRunnerзависит от него (по логике) , и он будет работать внутри от основных в @Testметоде, во время вызова JUnitCore.runClasses(TestMockitoJUnitRunner.class). Этот метод гарантирует, что главный бегун будет правильно запущен до запуска static class TestMockitoJUnitRunnerвспомогательного, эффективно реализуя несколько вложенных @RunWithаннотаций с зависимыми тестовыми классами.

Также на https://bekce.github.io/junit-multiple-runwith-dependent-tests


3
Звоня JUnitCore.runClasses()без проверки результата, вы рискуете скрыть ошибки из внутреннего теста. assert(JUnitCore.runClasses(TestMockitoJUnitRunner.class).wasSuccessful());хотя бы сообщит вам об ошибке
— Роботник


2

В моем случае я пытался издеваться над некоторым методом в Spring bean и

MockitoAnnotations.initMocks(test);

не работает. Вместо этого вы должны определить этот bean-компонент для создания с использованием имитационного метода внутри вашего XML-файла, как показано ниже.

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

и добавьте этот bean-компонент с autowired внутри вашего тестового класса, как показано ниже.

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

0

проверьте эту ссылку https://bekce.github.io/junit-multiple-runwith-dependent-tests/, используя этот подход, я объединил @RunWith (Parameterized.class) - внешний бегун - с @RunWith (MockitoJUnitRunner.class) - внутренний бегун. Единственная настройка, которую мне пришлось добавить, - это сделать мои переменные-члены во внешнем классе / бегунке статическими, чтобы сделать их доступными для внутреннего / вложенного бегуна / класса. Удачи и наслаждайся.


0

Я хотел запустить SWTBotJunit4ClassRunner и org.junit.runners.Parameterized одновременно, у меня есть параметрические тесты, и я хочу делать снимки экрана, когда тест SWT не проходит (функция скриншотов предоставляется SWTBotJunit4ClassRunner ). Ответ @bekce великолепен, и сначала я хотел пойти по этому пути, но это было либо странно, чем аргументы. Или выполнить параметризацию в подклассе и потерять информацию о том, какие именно тесты прошли / не прошли и имеют только последний снимок экрана (поскольку имена снимков экрана получают имя из самого теста). Так что в любом случае это было немного грязно.

В моем случае SWTBotJunit4ClassRunner достаточно прост, поэтому я клонировал исходный код класса, дал ему свое собственное имя ParametrizedScreenshotRunner и там, где оригинал расширял TestRunner , мой класс расширяет класс Parameterized, поэтому по сути я могу использовать свой собственный бегун вместо двух предыдущих. Мой собственный бегун расширяется поверх параметризованного бегуна, реализуя поверх него функцию скриншотов, теперь мой тест использует этот «гибридный» бегун, и все тесты сразу работают, как ожидалось (не нужно ничего менять внутри тестов).

Вот как это выглядит (для краткости я удалил все комментарии из листинга):

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

Вы также можете попробовать это:

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

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

2
Это не сработает, будет обработана только аннотация подкласса.
— PaulNUK

не работает - только MockitoJUnitRunner аннотации будут приниматься во внимание
— Przemek Bielicki
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.