@MockBean
如果您的依赖ClassUnderTest
项由接口表示,则注入带有注释的模拟 bean是有效的。假设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
注释
正如Sergio在评论部分中提到的,您可以使用@Replaces
注释替换基于类的 bean 依赖项。考虑以下示例:
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
,并指示 Micronaut 的 DI 机制将Dependency
bean替换为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();
}
}