如何用mock重写@Produces

时间:2015-07-22 00:32:52

标签: java unit-testing mockito cdi java-ee-7

我有一个类可以生成一个ElasticSearch客户端,以便与@Inject

一起使用
@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);
    }
}

测试-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;
    }
}

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

1 个答案:

答案 0 :(得分:2)

您需要记住始终编写可测试的代码。假设你的课程写得像这样

 $rotation = 135;
 $handle_rotated = imagerotate($handle_not_rotated,$rotation,0);
 imagealphablending($handle_rotated, true);
 imagesavealpha($handle_rotated, true); 

这有效,但不是非常可测试的。您可能希望使用模拟进行单元测试,没有活动连接。我们可以重构这一点,以便更加可测试。考虑这个替代实现:

@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 } } 文件中激活此替代方案。