如何用模拟重写@Produces



我有一个类,它生成一个用于@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文件中激活这个选项。

相关内容

  • 没有找到相关文章

最新更新