在 Micronaut 测试中覆盖依赖项

2022-09-04 01:16:02

我正在测试一个Micronaut类,其中注入了一个豆子。在我的测试中,我提供了一个类来覆盖它。然而,Micronaut似乎仍然注入了真正的依赖性。@MockBean

@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


答案 1

如果 中的依赖项由接口表示,则注入带有注释的模拟 Bean 是有效的。假设是一个简单的界面,例如:@MockBeanClassUnderTestDependency

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!");
    }
}

现在,出于测试目的,您可以定义一个 mock 来替换 :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);
    }

}

将执行此测试,并使用 方法返回的 mock 代替 。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...");
        }
    }
}

在这个例子中,我们定义了一个类,我们指示Micronaut的DI机制用.但是,我们需要记住一件重要的事情 - 因为我们的扩展类,父构造被调用。在这种情况下,您在问题中显示的示例将不起作用,因为抛出和测试失败。在这个修改后的示例中,我使用了如下类:MockDependencyDependencyMockDependencyMockDependencyDependencyDependency.<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...

与 相比,主要区别在于,如果您使用的是具体的类对象。作为解决方法(如果我们真的需要一个Mockito模拟对象)是在内部创建一个模拟并将调用委托给这个对象,如下所示:@MockBean@Replaces

@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();
    }
}

答案 2

推荐