Внедрение фиктивного bean-компонента с аннотацией @MockBean
работает, если ваша зависимость в ClassUnderTest
представлена интерфейсом. Допустим, Dependency
- это простой интерфейс вроде:
package di.failure.example;
public interface Dependency {
void run();
}
Ваше приложение может предоставлять реализацию этого интерфейса под названием DependencyImpl
:
package di.failure.example;
import javax.inject.Singleton;
@Singleton
public class DependencyImpl implements Dependency {
@Override
public void run() {
throw new RuntimeException("I don't want this to load!");
}
}
Теперь для целей тестирования вы можете определить макет, который заменяет DependencyImpl
:
package di.failure.example;
import io.micronaut.test.annotation.MicronautTest;
import io.micronaut.test.annotation.MockBean;
import org.junit.jupiter.api.Test;
import javax.inject.Inject;
import static org.mockito.Mockito.mock;
@MicronautTest
public class ClassUnderTestTest {
@Inject
ClassUnderTest classUnderTest;
@Test
public void test() {
classUnderTest.run();
}
@MockBean(DependencyImpl.class)
public Dependency dependency() {
return mock(Dependency.class);
}
}
Этот тест выполняется, и макет, возвращаемый методом dependency()
, используется вместо DependencyImpl
.
Использование аннотации @Replaces
Как упоминалось в разделе комментариев Серджио, вы можете заменить зависимость bean-компонента на основе классов, используя _ 12_ аннотация. Рассмотрим следующий пример:
package di.failure.example;
import io.micronaut.context.annotation.Replaces;
import io.micronaut.test.annotation.MicronautTest;
import org.junit.jupiter.api.Test;
import javax.inject.Inject;
import javax.inject.Singleton;
@MicronautTest
public class ClassUnderTestTest {
@Inject
ClassUnderTest classUnderTest;
@Test
public void test() {
classUnderTest.run();
}
@Replaces(Dependency.class)
@Singleton
public static class MockDependency extends Dependency {
public MockDependency() {
System.out.println("MockDependency.<init>");
}
@Override
void run() {
System.out.println("Does not throw any exception...");
}
}
}
В этом примере мы определили класс MockDependency
и инструктируем механизм DI Micronaut заменить bean-компонент Dependency
на MockDependency
. Однако есть одна важная вещь, о которой нам нужно помнить - поскольку наш MockDependency
расширяет Dependency
класс, вызывается родительская конструкция. Пример, который вы показали в вопросе, не будет работать в этом случае, потому что Dependency.<init>
выдает RuntimeException
и тест не проходит. В этом модифицированном примере я использовал такой класс:
package di.failure.example;
import javax.inject.Singleton;
@Singleton
public class Dependency {
public Dependency() {
System.out.println("Dependency.<init>");
}
void run() {
throw new RuntimeException("I don't want this to load!");
}
}
Когда я запускаю тест, он проходит, и я вижу следующий вывод консоли:
Dependency.<init>
MockDependency.<init>
Does not throw any exception...
Основное отличие от @MockBean
в том, что в случае @Replaces
вы используете конкретный объект класса. В качестве обходного пути (если нам действительно нужен объект-макет Mockito) является создание макета внутри и делегирование вызовов этому объекту, примерно так:
@Replaces(Dependency.class)
@Singleton
public class MockDependency extends Dependency {
private final Dependency delegate;
public MockDependency() {
this.delegate = mock(Dependency.class);
}
@Override
void run() {
delegate.run();
}
}
person
Szymon Stepniak
schedule
03.11.2018