0

我正在为以下扩展 WCMUsePOJO 的类编写单元测试用例。现在,此类正在使用如下所示的 getSlingScriptHelper 方法。

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);
}
} 
4

3 回答 3

2

这是一种可能的解决方案。主要思想是让你的类有一个真实的对象,但被覆盖getSlingScriptHelper()以返回 mocked 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);
    }
}
于 2017-08-12T06:58:58.577 回答
2

The only thing that you should "have to"* mock is the SlingScriptHelper instance itself, so that it will mimic the dependency injection of the declared service.

Everything else (e.g. the Bindings instance) can be a concrete implementation, for example:

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

}

The entry point here, as you said above, is via the init() method of the WCMUsePojo superclass (as this method is an implementation of the Use.class interface, this test structure also works for testing that via that interface, even if you don't use WCMUsePojo directly.)

*this could be any type of test-double, not necessarily a mock.

于 2017-08-15T08:17:20.390 回答
2

ConstantsServiceProvider.class如果要对其进行单元测试,则不应创建模拟。相反,您应该创建其内部对象的模拟。所以:

  1. 创建ConstantsServiceProviderwith的真实实例new
  2. 方法返回的模拟对象getSlingScriptHelper().getService(.)。通常,依赖项是由某个容器(如Spring应用程序的其他类)使用 setter 提供(注入)或简单地提供给类的。在这两种情况下,创建模拟都很容易。
  3. 如果您当前的实现不允许这样做 - 考虑重构。
  4. 您正在测试void activate()不返回任何内容的方法。因此,您应该验证调用 constantsService.getVar1()方法。

我强烈建议你学习Vogella 单元测试教程

于 2017-08-11T22:00:02.887 回答