如果您在ClassUnderTest 中的依赖项由接口表示,则使用@MockBean 注释注入模拟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注解
正如 cmets 部分中提到的 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();
}
}