EJB没有接口视图测试(arquillain& mockito)

时间:2016-04-01 12:29:06

标签: java ejb mockito ejb-3.1 jboss-arquillian

我正在研究Java EE 7(在wildfly 9.0.2上)应用程序,我偶然发现了一篇文章http://www.oracle.com/technetwork/articles/java/intondemand-1444614.html。主要是关于:

  

过早的可扩展性是某些邪恶的根源

在我遇到的某些情况下这是有道理的。我已经将一些类更改为无接口视图。实现本身不是问题,但测试是。

例如,我有这两个类。

@Stateless
public class SomeBean {
     public String getText()
     {
         return "Test text";
     }
}

@Stateless
public class SomeOtherBean {
    @Inject
    private SomeBean someBean;

    public String getText()
    {
        return someBean.getText();
    }
}

我想要某种方式,someBean属性最好被模拟对象覆盖。不改变SomeBeanSomeOtherBean类。我已经尝试了一些例子,但它们没有用于例如: https://github.com/arquillian/arquillian-showcase/tree/master/extensions/autodiscover/src/test/java/org/jboss/arquillian/showcase/extension/autodiscover

以前是否有人遇到此问题并有解决方案?

2 个答案:

答案 0 :(得分:4)

我最终使用了2个解决方案。

解决方案1:将mockito用于内部或更小的测试

为了测试特定类,Mockito非常有用,因为它支持依赖注入。

@RunWith(MockitoJUnitRunner.class)
public class SomeOtherBeanTest {
    @Mock
    private SomeBean someBean;

    @InjectMocks
    private SomeOtherBean someOhterBean;

    @Before
    public void setUp() {
        Mockito.when(someBean.getText()).thenReturn("Overwritten!");
    }

    @Test
    public void testGetText() throws Exception {
        assertEquals("Overwritten!", someOhterBean.getText());
    }
}

解决方案2:使用@Produces和@Alternatives模拟外部服务(例如模拟OAuth2服务器)或更大的测试(例如集成测试)

首先,我创建一个新的@Alternative注释:

@Alternative
@Stereotype
@Retention(RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
public @interface CDIMock {}

然后将此作为构造型添加到arquillian beans.xml部署中:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
       bean-discovery-mode="all">
    <alternatives>
        <stereotype>com.project.CDIMock</stereotype>
    </alternatives>
</beans>

之后,在单独的类中创建一个新的@Producer方法:

public class SomeBeanMockProducer {
    @Produces @CDIMock
    public static SomeBean produce() {
        SomeBean someBean = Mockito.mock(SomeBean.class);
        Mockito.when(someBean.getText()).thenReturn("mocked");

        return someBean;
    }  
}

SomeBeanMockProducer类添加到arquillian部署中,您应该让它工作。

此解决方案的替代方法是使用@Specializes并扩展SomeBean实现。在我看来,这并没有给我足够的控制,比如@Alternative + Mocking解决方案(在我的例子中为@CDIMock)。

例如,假设我SomeBean具有调用远程服务器的方法。如果我为此添加一个方法而忘记在@override类中@Specializes这将进行真正的远程调用,那么Mocking就不会这样了。

答案 1 :(得分:0)

很明显,将Mock或其他专用对象替换为注入的无接口类更加困难,因为这不是你为bean声明接口所需要的。

话虽如此,如果您没有运行CDI容器(例如进行POJO单元测试),我认为使用Mockito是最简单的方法。

如果你想这样做,纯粹的CDI&#34;在容器内部,您可以使用CDI的Alternative和Specialization机制,如Java EE 6 tutorial中所述。

@Specializes
public class SomeBeanMock extends SomeBean {

    @Overrides         
    public String getText()
     {
         return "mock";
     }
}

当然,你只能使用子类原始bean的模拟(因为你没有接口),并且你只能使用通常的可见性规则。更改/模拟私有字段或方法需要反射或字节码操作(这是Mockito幕后操作)。