JUnit 更改集成测试中的类或方法行为

我有一个java应用程序(里面没有Spring),我想用集成测试来测试它。


我的主要用例是主要功能,它使用指定的输入在数据库上执行一些操作并向两个不同的服务(一个 SOAP 和一个 REST)发送一些请求。


现在我有一个有效的 JUnit 配置(分为单元测试和集成测试)+ io.fabric8:docker-maven-plugin,它在集成测试期间使用 docker 映像作为数据库。


我想做的是为这两个服务添加模拟,特别是用于直接调用外部服务的方法。


最大的问题是我有这样的结构:


class A{

    Result mainFunction(Request r){

        ....

        B b = new B(params);

        b.logEvent(someParameters)

        ....

    }

}

class B{

    int logEvent(Object someParameters){

        ....

        NotifierHandler nh = new NotifierHandler(param1);

        nh.sendNotification(json);

        ....

    }

}

我在哪里:


class NotifierHandler{

    String sendNotification(Json j){

        ...

        [call to REST service with some parameters]

        ...

        ...

        [call to SOAP service with some parameters]

        ...

    }

}

我需要什么:A.mainFunction(r)在测试环境中调用,用 FakeNotifierHandler 替换 NotifierHandler 和/或更改方法的行为sendNotification()。


实际问题:现在使用 Mockito 和 PowerMock 时遇到的问题是,我无法使用 FakeNotifierHandler 全局直接更改类 NotifierHandler。同样尝试改变该方法的行为。


特别是,我需要的是创建一个


class FakeNotifierHandler{

    String sendNotification(Json j){

        ...

        [save on an HashMap what I should send to the REST service]

        ...

        ...

        [save on another HashMap what I should send to the SOAP service]

        ...

    }

}

阅读我尝试过的所有示例,我只看到了更改方法返回值的简单示例,而不是更改一个类的一个方法的行为,该方法被另一个类和另一个我用作集成测试起点的类所使用。


注意:可能有一种快速的方法可以做到这一点,但我对这种类型的测试(Mockito,PowerMock,...)非常陌生,并且我没有找到这种特殊奇怪情况的示例。



慕沐林林
浏览 117回答 1
1回答

繁星coding

我找到了一个非常有效的解决方案,而且非常简单!解决方案是 PowerMock(https://github.com/powermock/powermock),特别是用另一个类实例替换类实例的创建: https:&nbsp;//github.com/powermock/powermock/wiki/mockito#how-模拟新对象的构造我的项目中只有一个问题,那就是 JUnit 5。PowerMock 支持 JUnit 4,因此,仅在解决方案的某些测试中使用它。为了做到这一点,需要更换import&nbsp;org.junit.jupiter.api.Test;和import&nbsp;org.junit.Test;为了使用“&nbsp;whenNew()&nbsp;”方法,我扩展了测试中必须替换的类,并且仅覆盖了集成测试所需的方法。此解决方案的最大好处是我的代码未受影响,并且我也可以在旧代码上使用此方法,而无需在代码重构期间引入回归的风险。关于集成测试的代码,这里有一个例子:import org.junit.jupiter.api.DisplayName;import org.junit.Test;import org.junit.runner.RunWith;import org.powermock.api.mockito.PowerMockito;import org.powermock.core.classloader.annotations.PowerMockIgnore;import org.powermock.core.classloader.annotations.PrepareForTest;import org.powermock.modules.junit4.PowerMockRunner;@RunWith(PowerMockRunner.class)@PowerMockIgnore({"javax.crypto.*" }) // https://github.com/powermock/powermock/issues/294@PrepareForTest(LegacyCoreNetworkClassPlg.class) // it is the class that contains the "new SOAPCallHelper(..)" code that I want to intercept and replace with a stubpublic class ITestExample extends InitTestSuite {&nbsp; &nbsp; @Test&nbsp; &nbsp; @DisplayName("Test the update of a document status")&nbsp; &nbsp; public void iTestStubLegacyNetworkCall() throws Exception {&nbsp; &nbsp; &nbsp; &nbsp; // I'm using JUnit 4&nbsp; &nbsp; &nbsp; &nbsp; // I need to call @BeforeAll defined in InitTestSuite.init();&nbsp; &nbsp; &nbsp; &nbsp; // that works only with JUnit 5&nbsp; &nbsp; &nbsp; &nbsp; init();&nbsp; &nbsp; &nbsp; &nbsp; LOG.debug("IN stubbing...");&nbsp; &nbsp; &nbsp; &nbsp; SOAPCallHelperStub stub = new SOAPCallHelperStub("empty");&nbsp; &nbsp; &nbsp; &nbsp; PowerMockito.whenNew(SOAPCallHelper.class).withAnyArguments().thenReturn(stub);&nbsp; &nbsp; &nbsp; &nbsp; LOG.debug("OUT stubbing!!!");&nbsp; &nbsp; &nbsp; &nbsp; LOG.debug("IN iTestStubLegacyNetworkCall");&nbsp; &nbsp; &nbsp; &nbsp; ...&nbsp; &nbsp; &nbsp; &nbsp; // Here I can create any instance of every class, but when an instance of&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; // LegacyCoreNetworkClassPlg.class is created directly or indirectly, PowerMock&nbsp; &nbsp; &nbsp; &nbsp; // is checking it and when LegacyCoreNetworkClassPlg.class will create a new&nbsp; &nbsp; &nbsp; &nbsp; // instance of SOAPCallHelper it will change it with the&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; // SOAPCallHelperStub instance.&nbsp; &nbsp; &nbsp; &nbsp; ...&nbsp; &nbsp; &nbsp; &nbsp; LOG.debug("OUT iTestStubLegacyNetworkCall");&nbsp; &nbsp; }}这里是pom.xml的配置&nbsp; &nbsp; <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>&nbsp; &nbsp; <junit.jupiter.version>5.5.2</junit.jupiter.version>&nbsp; &nbsp; <junit.vintage.version>5.5.2</junit.vintage.version>&nbsp; &nbsp; <junit.platform.version>1.3.2</junit.platform.version>&nbsp; &nbsp; <junit.platform.engine.version>1.5.2</junit.platform.engine.version>&nbsp; &nbsp; <powermock.version>2.0.2</powermock.version>&nbsp; &nbsp; <!-- FOR TEST -->&nbsp; &nbsp; <dependency>&nbsp; &nbsp; &nbsp; &nbsp; <groupId>org.junit.jupiter</groupId>&nbsp; &nbsp; &nbsp; &nbsp; <artifactId>junit-jupiter-api</artifactId>&nbsp; &nbsp; &nbsp; &nbsp; <version>${junit.jupiter.version}</version>&nbsp; &nbsp; &nbsp; &nbsp; <scope>test</scope>&nbsp; &nbsp; </dependency>&nbsp; &nbsp; <dependency>&nbsp; &nbsp; &nbsp; &nbsp; <groupId>junit</groupId>&nbsp; &nbsp; &nbsp; &nbsp; <artifactId>junit</artifactId>&nbsp; &nbsp; &nbsp; &nbsp; <scope>test</scope>&nbsp; &nbsp; </dependency>&nbsp; &nbsp; <!-- Only required to run tests in an IDE that bundles an older version -->&nbsp; &nbsp; <dependency>&nbsp; &nbsp; &nbsp; &nbsp; <groupId>org.junit.platform</groupId>&nbsp; &nbsp; &nbsp; &nbsp; <artifactId>junit-platform-launcher</artifactId>&nbsp; &nbsp; &nbsp; &nbsp; <version>${junit.platform.version}</version>&nbsp; &nbsp; &nbsp; &nbsp; <scope>test</scope>&nbsp; &nbsp; </dependency>&nbsp; &nbsp; <!-- Only required to run tests in an IDE that bundles an older version -->&nbsp; &nbsp; <dependency>&nbsp; &nbsp; &nbsp; &nbsp; <groupId>org.junit.jupiter</groupId>&nbsp; &nbsp; &nbsp; &nbsp; <artifactId>junit-jupiter-engine</artifactId>&nbsp; &nbsp; &nbsp; &nbsp; <version>${junit.jupiter.version}</version>&nbsp; &nbsp; &nbsp; &nbsp; <scope>test</scope>&nbsp; &nbsp; </dependency>&nbsp; &nbsp; <!-- Only required to run tests in an IDE that bundles an older version -->&nbsp; &nbsp; <dependency>&nbsp; &nbsp; &nbsp; &nbsp; <groupId>org.junit.vintage</groupId>&nbsp; &nbsp; &nbsp; &nbsp; <artifactId>junit-vintage-engine</artifactId>&nbsp; &nbsp; &nbsp; &nbsp; <version>${junit.vintage.version}</version>&nbsp; &nbsp; &nbsp; &nbsp; <scope>test</scope>&nbsp; &nbsp; </dependency>&nbsp; &nbsp; <dependency>&nbsp; &nbsp; &nbsp; &nbsp; <groupId>org.junit.platform</groupId>&nbsp; &nbsp; &nbsp; &nbsp; <artifactId>junit-platform-engine</artifactId>&nbsp; &nbsp; &nbsp; &nbsp; <version>${junit.platform.engine.version}</version>&nbsp; &nbsp; &nbsp; &nbsp; <scope>test</scope>&nbsp; &nbsp; </dependency>&nbsp; &nbsp; <dependency>&nbsp; &nbsp; &nbsp; &nbsp; <groupId>org.junit.jupiter</groupId>&nbsp; &nbsp; &nbsp; &nbsp; <artifactId>junit-jupiter-params</artifactId>&nbsp; &nbsp; &nbsp; &nbsp; <version>${junit.vintage.version}</version>&nbsp; &nbsp; &nbsp; &nbsp; <scope>test</scope>&nbsp; &nbsp; </dependency>&nbsp; &nbsp; <dependency>&nbsp; &nbsp; &nbsp; &nbsp; <groupId>org.powermock</groupId>&nbsp; &nbsp; &nbsp; &nbsp; <artifactId>powermock-module-junit4</artifactId>&nbsp; &nbsp; &nbsp; &nbsp; <version>${powermock.version}</version>&nbsp; &nbsp; &nbsp; &nbsp; <scope>test</scope>&nbsp; &nbsp; </dependency>&nbsp; &nbsp; <dependency>&nbsp; &nbsp; &nbsp; &nbsp; <groupId>org.powermock</groupId>&nbsp; &nbsp; &nbsp; &nbsp; <artifactId>powermock-api-mockito2</artifactId>&nbsp; &nbsp; &nbsp; &nbsp; <version>${powermock.version}</version>&nbsp; &nbsp; &nbsp; &nbsp; <scope>test</scope>&nbsp; &nbsp; </dependency>
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java