2017-08-11 156 views
0

我正在爲擴展WCMUsePOJO的以下類編寫單元測試用例。現在,這個類正在使用如下所示的getSlingScriptHelper方法。單元測試WCMUsePOJO類

public class ConstantsServiceProvider extends WCMUsePojo { 
private static final Logger logger = LoggerFactory.getLogger(ConstantsServiceProvider.class); 

private String var1; 

@Override 
public void activate() throws Exception { 
    ConstantsService constantsService = getSlingScriptHelper().getService(ConstantsService.class); 
    if(constantsService != null) { 
     var1 = constantsService.getVar1(); 
    } 
} 

public string getVar1() { return var1; } 

} 

問題是我該如何模擬getSlingScriptHelper方法?以下是我的單元測試代碼。

公共類ConstantsServiceProviderTest {

@Rule 
public final SlingContext context = new SlingContext(ResourceResolverType.JCR_MOCK); 

@Mock 
public SlingScriptHelper scriptHelper; 

public ConstantsServiceProviderTest() throws Exception { 

} 

@Before 
public void setUp() throws Exception { 
    ConstantsService service = new ConstantsService(); 
    scriptHelper = context.slingScriptHelper(); 
    provider = new ConstantsServiceProvider(); 

    provider.activate(); 
} 

@Test 
public void testGetvar1() throws Exception { 
    String testvar1 = ""; 
    String var1 = provider.getVar1(); 
    assertEquals(testvar1, var1); 
} 
} 

回答

2

如果你想單元測試你不應該創建一個ConstantsServiceProvider.class模擬。相反,你應該創建其內部對象的模擬。所以:

  1. 與由getSlingScriptHelper().getService(.)方法返回new
  2. Mock對象創建的ConstantsServiceProvider真正的實例。通常,通過某些容器(如Spring)向類提供(注入)依賴項,或者僅由其他類的應用程序使用setter提供依賴項。在這兩種情況下,模擬創作都很容易。
  3. 如果你當前的實現不允許這樣做 - 考慮重構。
  4. 您正在測試void activate()方法,它不返回任何內容。所以,你應該驗證調用constantsService.getVar1()方法。

我強烈建議你學習Vogella unit-testing tutorial

2

這裏的可能的解決方案之一。 主要想法是讓你的班級有一個真實的對象,但重寫getSlingScriptHelper()返回嘲笑scriptHelper

我嘲笑ConstantsService以及可能不需要,我不知道你的代碼。

public class ConstantsServiceProviderTest { 
    @Mock 
    public SlingScriptHelper scriptHelper; 

    @Test 
    public void getVar1ReturnsActivatedValue() throws Exception { 
     // setup 
     final String expectedResult = "some value"; 

     // Have a mocked ConstantsService, but if possible have a real instance. 
     final ConstantsService mockedConstantsService = 
      Mockito.mock(ConstantsService.class); 
     Mockito.when(
      mockedConstantsService.getVar1()) 
       .thenReturn(expectedResult); 

     Mockito.when(
      scriptHelper.getService(ConstantsService.class)) 
       .thenReturn(mockedConstantsService); 

     // Have a real instance of your class under testing but with overridden getSlingScriptHelper() 
     final ConstantsServiceProvider providerWithMockedHelper = 
      new ConstantsServiceProvider() { 
       @Override 
       SlingScriptHelper getSlingScriptHelper() { 
        return scriptHelper; 
       } 
      }; 

     // when 
     String actualResult = providerWithMockedHelper.getVar1(); 

     // then 
     assertEquals(expectedResult, actualResult); 
    } 
} 
+0

非常感謝。我能夠讓slingscripthelper工作。和我的方法是非常類似於您的解決方案,除了一個額外的添加。我也必須模擬Bindings類。 (綁定.get(「sling」));然後返回(context.slingScriptHelper());' ''添加這個然後調用'provider.init(bindings)'方法。這將最終運行activate方法,因爲它已經在** init()**中被調用了。 – romie99

+0

如果您覺得這是正確的,可以將其添加到您的解決方案中。我會將你的答案標記爲正確答案。 :) – romie99

+0

是的,在你的真實項目你應該有正確的版本。在Stackoverflow上,一些細節可能會被忽略,因爲目標是提供主要思想來解鎖作者。在你的情況下,我不知道'init()'和'Binding',因爲它在原來的文章中錯過了,所以我建議保留所有'原樣'以符合你的問題。 –

1

,你應該唯一「必須」 *模擬是SlingScriptHelper實例本身,因此它會模仿申報服務的依賴注入。

其他一切(例如綁定實例)可以是一個具體的實現,例如:

import org.apache.sling.api.scripting.SlingBindings; 
import org.apache.sling.api.scripting.SlingScriptHelper; 
import org.junit.Test; 

import javax.script.Bindings; 
import javax.script.SimpleBindings; 

import static org.hamcrest.CoreMatchers.equalTo; 
import static org.hamcrest.CoreMatchers.is; 
import static org.hamcrest.MatcherAssert.assertThat; 
import static org.mockito.Mockito.mock; 
import static org.mockito.Mockito.when; 

public class ConstantsServiceProviderTest { 

    private SlingScriptHelper mockSling = mock(SlingScriptHelper.class); 
    private ConstantsServiceProvider constantsServiceProvider = new ConstantsServiceProvider(); 
    private Bindings bindings = new SimpleBindings(); 

    @Test 
    public void testFoo() throws Exception { 
     //Arrange 
     final String expected = "Hello world"; 
     final ConstantsService testConstantsService = new TestConstantsService(expected); 
     when(mockSling.getService(ConstantsService.class)).thenReturn(testConstantsService); 
     bindings.put(SlingBindings.SLING, mockSling); 

     //Act 
     constantsServiceProvider.init(bindings); 

     //Assert 
     final String actual = constantsServiceProvider.getVar1(); 
     assertThat(actual, is(equalTo(expected))); 
    } 

    class TestConstantsService extends ConstantsService { 
     String var1 = ""; 

     TestConstantsService(String var1) { 
      this.var1 = var1; 
     } 

     @Override 
     String getVar1() { 
      return var1; 
     } 
    } 

} 

入口點在這裏,因爲你上面說的,是通過WCMUsePojo超的init()方法(因爲這方法是Use.class接口的實現,該測試結構也適用於通過該接口進行測試,即使您不直接使用WCMUsePojo也是如此。)

*這可能是任何類型的測試雙,不一定是嘲笑。