2011-02-28 48 views
14

是否有可能在Arquillian中使用某種模擬框架,或者精確地如何模擬注入的EJB?我知道,通過使用CDI(上下文和依賴注入),可以在測試中注入替代品。但是,如果沒有CDI作爲注入機制,那麼當我只使用EJB注入時,這是如何實現的?如何用Arquillian模擬服務?

最近我已經測試我的服務接口模擬實現的EJB如下:

// Service inteface 
public interface Audit { 
    void audit(String info); 
} 

// Mock implementation 
@Stateless 
public class MockAuditBean implements Audit { 

    public static String lastInfo = null; 

    @Override 
    public void audit(String info) { 
     this.lastInfo = info; 
    } 
} 

// assert in test 
assertTrue(MockAuditBean.lastInfo.contains("dummy")); 

這種方法是可行的,但需要大量的定製模擬實現的。更糟糕的是,注入的mock實例是代理服務器並使用服務接口。這些不能轉換爲模擬實現類來比較結果。只能使用靜態成員和模擬實現方法。

我也測試了另一種手動設置相關EJB的可能性。這種方法有幾個缺點。它要求測試的目標EJB具有非私有成員或設置者。當目標EJB依賴@PostConstruct生命週期註釋時,必須在手動「注入」設置後調用它。 這個解決方案的優點是可以使用模擬框架,比如mockito或者jMock。

有人有共享經驗,如何測試和設置這樣的集成測試,甚至使用嘲笑框架呢?

回答

2

IMO,EJB沒有設計考慮到測試。你的選擇聽起來像是一個足夠妥協,我會去做。使用mockito是一大優點,我甚至在使用CDI時也使用它。

我會使用「默認」成員範圍和javadoc到其他開發人員訪問它們僅用於測試目的。

0

如果你真的想在你的集成測試中與模擬進行交互(例如一個原因可能是你還沒有完整的實現,或者你沒有控制過外部系統的外觀),將Mockito與Arquillian測試相結合是一種非常簡單的方法,請參閱this example from the showcase。它實際上是擴展,但不是一個發佈。

1

本文從Oracle示出了一種方法用於使用JUnit和測試的Mockito爲「注入」的EJB: http://www.oracle.com/technetwork/articles/java/unittesting-455385.html

編輯: 基本上的Mockito列入允許嘲笑對象像的EntityManager等:

import static org.mockito.Mockito.*; 

...

em = mock(EntityManager.class); 

他們顯示了EJB的方法以及使用mockito。給定一個EJB:

@Stateless 
public class MyResource { 
@Inject 
Instance<Consultant> company; 

@Inject 
Event<Result> eventListener; 

測試可以「注入」這些對象:

public class MyResourceTest { 

private MyResource myr; 
@Before 
public void initializeDependencies(){ 
this.myr = new MyResource(); 
this.myr.company = mock(Instance.class); 
this.myr.eventListener = mock(Event.class); 
} 

注意MyResource和MyResource在同一個類路徑,但不同的源文件夾,這樣你的測試訪問受保護字段,companyeventListener


編輯:

注意:您可以使用JBoss的從FacesMockitoRunnerhttps://community.jboss.org/thread/170800),以獲得共同的JSF組件完成這件事,並使用註釋爲其他人(的Java EE 6 CDI啓用作爲預必要對於這一點,但不要求JBoss服務器):

  1. 包括JSF,的Mockito和JSF的依賴關係的Mockito在行家:

    <dependency> 
         <groupId>junit</groupId> 
         <artifactId>junit</artifactId> 
         <version>4.11</version> 
         <scope>test</scope> 
        </dependency> 
        <dependency> 
         <groupId>org.mockito</groupId> 
         <artifactId>mockito-core</artifactId> 
         <version>1.9.5</version> 
         <scope>test</scope> 
        </dependency> 
        <dependency> 
         <groupId>org.jboss.test-jsf</groupId> 
         <artifactId>jsf-mockito</artifactId> 
         <version>1.1.7-SNAPSHOT</version> 
         <scope>test</scope> 
        </dependency> 
    
  2. @RunWith註釋添加到您的測試:

    @Inject 
    FacesContext facesContext; 
    @Inject 
    ExternalContext ext; 
    @Inject 
    HttpServletRequest request; 
    
  3. 模擬使用註釋@org.mockito.Mock任何其他對象(它出現FacesMockitoRunner稱此爲:使用註釋

    @RunWith(FacesMockitoRunner.class) 
    public class MyTest { 
    
  4. 進樣常見的面對象所以在這裏可能不需要):

    @Mock MyUserService userService; 
    @Mock MyFacesBroker broker; 
    @Mock MyUser user; 
    
  5. 初始化注入的嘲弄使用

    @Before public void initMocks() { 
        // Init the mocks from above 
        MockitoAnnotations.initMocks(this); 
    } 
    
  6. 設置你的測試和往常一樣:

    assertSame(FacesContext.getCurrentInstance(), facesContext); 
    when(ext.getSessionMap()).thenReturn(session); 
    assertSame(FacesContext.getCurrentInstance().getExternalContext(), ext); 
    assertSame(FacesContext.getCurrentInstance().getExternalContext().getSessionMap(), ext.getSessionMap()); 
    

+0

你能至少要解釋一些鏈接的內容?僅鏈接就會受到「鏈接腐爛」的影響,我們將讚賞這種努力。 – trudyscousin 2013-01-25 18:33:24

1

你可能想看看testfun-JEE這允許您在容器外單元測試(而不是集成測試)您的EJB。 testfun-JEE負責將EJB以及EntityManager和一些標準資源直接注入到您的測試類中 - 將這些EJB中的引用自動解析到其他EJB中。

最酷的是你可以通過簡單地向你的測試添加一個成員變量來模擬任何依賴關係,測試註釋爲@Mock - testfun-JEE會在需要的地方注入這個模擬。

請參閱https://github.com/michaelyaakoby/testfun中的示例。

順便說一下,雖然這個框架最近出版(像今天...),但它在我公司已經被廣泛使用了一年多了。

0

使用框架,如Mockito。

不幸的是,Arquillian不會自動包含必要的依賴關係。 您可以在@Deployment功能添加它們:

@Deployment 
public static WebArchive deploy() 
{ 
    return ShrinkWrap.create(WebArchive.class) 
     .addAsLibraries(// add maven resolve artifacts to the deployment 
      DependencyResolvers.use(MavenDependencyResolver.class) 
      .artifact("org.mockito:mockito-all:1.8.3") 
      .resolveAs(GenericArchive.class)) 
     ); 
} 

source

然後在您的@Test方法,你可以使用:

mock(MockedService.class).methodName() 

這github上展示顯示了一個辦法,讓自動發現,這似乎需要一些設置: source