我正在测试一个Micronaut类,其中已经注入了一个bean。在我的测试中,我提供了一个@MockBean
类来覆盖它。但是,似乎Micronaut仍然注入了真正的依赖性。
@MicronautTest
public class ClassUnderTestTest {
@Inject ClassUnderTest classUnderTest;
@Test
public void test() {
}
@MockBean
Dependency dependency() {
return mock(Dependency.class);
}
}
我向Github上传了一个最低版本:https://github.com/crummy/micronaut-test-dependencies。真正的依赖关系会引发异常,测试也是如此。我不会因为@MockBean
而发生这种情况。
如果我将注释更改为@MockBean(Dependency.class)
,则会出现此错误:Message: No bean of type [di.failure.example.Dependency] exists
。这似乎让我更加困惑-现在无法解决我的真实或模拟依赖项?
答案 0 :(得分:8)
如果您在@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();
}
}