繁体   English   中英

如何使用模拟覆盖@Produces

[英]How to override @Produces with a mock

我有一个类产生一个与@Inject一起使用的ElasticSearch客户端

@Produces
@ApplicationScoped
public Client createClient() {
    return new TransportClient().addTransportAddress(new InetSocketTransportAddress(IP, 9300));
}

我想在单元测试中使用以下类似方法模拟此客户端

@Produces
@Mock
private Client client;

这将导致AmbiguousResolutionException,因为同一bean有两个提供程序。

如何仅将模拟生成的类优先用于单元测试?


从下面的评论中,我进行了以下更改。 我在替代方法中设置了一个断点,但没有受到打击。

ElasticSearchProducer.java

@ApplicationScoped
public class ElasticSearchProducer {

    public static final String IP = "10.9.215.28";

    private Client client;

    @PostConstruct
    public void init() {
        client = createClient();
    }

    protected Client createClient() {
        return new TransportClient().addTransportAddress(new InetSocketTransportAddress(IP, 9300));
    }

    @Produces
    @ApplicationScoped
    public Client getClient() {
        return client;
    }
}

ElasticSearchProducerAlternative.java

@Alternative
@ApplicationScoped
public class ElasticSearchProducerAlternative extends ElasticSearchProducer {

    @Override
    public Client createClient() {
        return Mockito.mock(Client.class);
    }
}

test-beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">

    <alternatives>
        <class>com.walmart.platform.pv.cdi.ElasticSearchProducerAlternative</class>
    </alternatives>

</beans>

ArquillianTest.java

@RunWith(Arquillian.class)
public abstract class ArquillianTest {
    @Deployment(testable = true)
    public static WebArchive createDeployment() {


        WebArchive war = ShrinkWrap.create(WebArchive.class, "quintessence.war")
                .addPackages(true, "com.w.platform");

        war.merge(ShrinkWrap.create(GenericArchive.class).as(ExplodedImporter.class)
                        .importDirectory("src/main/webapp").as(GenericArchive.class),
                "/", Filters.includeAll());

        war.addAsManifestResource("etc/conf/test/import.sql");
        war.addAsManifestResource("test-persistence.xml", "persistence.xml");
        war.addAsWebInfResource("test-beans.xml", "beans.xml");
        war.addAsWebInfResource("test-resources.xml", "resources.xml");

        System.out.println(war.toString(true));
        return war;
    }
}

在我的测试中,未使用替代类

您需要记住始终编写可测试的代码。 假设您的班级是这样写的

@ApplicationScoped
public class ESClient {
    @Produces
    @ApplicationScoped
    public Client createClient() {
        return new TransportClient().addTransportAddress(new InetSocketTransportAddress(IP, 9300));
    }
}

这可行,但不是很可测试。 您可能要对单元测试使用模拟,没有活动的连接。 我们可以将其重构为更具可测试性。 考虑以下替代实现:

@ApplicationScoped
public class ESClient {
    private Client client;
    @PostConstruct
    public void init() {
         this.client = createClient();
    }
    @Produces
    @ApplicationScoped
    public Client getClient() {
        return this.client;
    }
    protected Client createClient() {
        return new TransportClient().addTransportAddress(new InetSocketTransportAddress(IP, 9300));
    }
}

是的,它有点冗长,但是您的关注点分离得更好。 然后,您可以在测试中提供替代实现

@ApplicationScoped
@Alternative
public class MockESClient extends ESClient {
    @Override
    protected Client createClient() {
        // return your mock here
    }
}

现在,您只需要在beans.xml文件中激活此替代方法即可。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM