Mockito
作为一个概念,我是新手。你能帮我理解Mockito
在 ATG 中使用表单处理程序吗?一些例子将不胜感激。
3 回答
其他类似问题有一个很好的答案(与 ATG 相关):using-mockito-for-writing-atg-test-case。请查看它是否包含您需要的内容。
众所周知,许多 ATG 特定组件(尤其是表单处理程序)“可测试性较低”(与使用 TDD/BDD 方法开发的组件相比),OOTB 组件(包括参考应用程序)的 b/c 设计并不总是遵守遵循“低耦合、高内聚”的原则
但是通用方法仍然适用于为所有 ATG 组件编写单元测试。
这是我对表单处理程序进行单元测试时所做的事情(至少在我设法发布 AtgDust 的主要更新之前)。请注意,我不使用通配符导入,所以我不确定这是否会导致任何命名空间冲突。
import static org.mockito.Mockito.*;
import static org.mockito.MockitoAnnotations.initMocks;
import org.junit.*;
import static org.junit.Assert.assertThat;
import static org.hamcrest.CoreMatchers.*;
import atg.servlet.*;
import some.form.handler.FormHandler;
@RunWith(JUnit4.class)
public class FormHandlerTest {
@Mock DynamoHttpServletRequest request;
@Mock DynamoHttpServletResponse response;
FormHandler handler;
@Before
public void setup() {
initMocks(this);
handler = new FormHandler();
}
@Test
public void testSubmitHandlerRedirects() {
handler.handleSubmit(request, response);
verify(response).sendLocalRedirect(eq("/success.jsp"), eq(request));
assertThat(handler.getFormError(), is(false));
}
}
基本思想是在模拟对象方法调用上使用 when() 为模拟/存根设置自定义行为,以返回一些测试值或抛出异常,然后 verify() 模拟对象被调用了准确的次数(默认情况下) case, once),并对表单处理程序中已更改的数据执行任何断言。本质上,您将希望使用 when() 来模拟需要返回其他模拟对象的任何类型的方法调用。你什么时候需要这样做?最简单的判断方法是当您由于使用空值、零、空字符串等而出现 NPE 或其他运行时异常时。
在集成测试中,理想情况下,您将能够使用一种介于两者之间的模拟/测试 servlet,它假装像一个完整的应用程序服务器一样工作,执行最小的请求/会话/全局范围管理。据我所知,这对 Arquillian 来说是一个很好的用途,但我还没有开始尝试。
下面是我们使用 Mockito 测试 ATG FormHandlers 的框架。显然,您需要进行所有适当的测试,但这应该可以帮助您入门。
public class AcmeFormHandlerTest {
@Spy @InjectMocks private AcmeFormHandler testObj;
@Mock private Validator<AcmeInterface> acmeValidatorMock;
@Mock private DynamoHttpServletRequest requestMock;
@Mock private DynamoHttpServletResponse responseMock;
private static final String ERROR1_KEY = "error1";
private static final String ERROR1_VALUE = "error1value";
@BeforeMethod(groups = { "unit" })
public void setUp() throws Exception {
testObj = new AcmeFormHandler();
initMocks(this);
}
//Test the happy path scenario
@Test(groups = { "unit" })
public void testWithValidData() throws Exception {
testObj.handleUpdate(requestMock, responseMock);
//Assume your formhandler calls a helper method, then ensure the helper method is called once. You verify the working of your helper method as you would do any Unit test
Mockito.verify(testObj).update(Matchers.refEq(requestMock), Matchers.refEq(responseMock), Mockito.anyString(), (AcmeBean) Mockito.anyObject());
}
//Test a validation exception
@Test(groups = { "unit" })
public void testWithInvalidData() throws Exception {
Map<String, String> validationMessages = new HashMap<String, String>();
validationMessages.put(ERROR1_KEY, ERROR1_VALUE);
when(acmeValidatorMock.validate((AcmeInterface) Mockito.any())).thenReturn(validationMessages);
testObj.handleUpdate(requestMock, responseMock);
assertEquals(1, testObj.getFormExceptions().size());
DropletFormException exception = (DropletFormException) testObj.getFormExceptions().get(0);
Assert.assertEquals(exception.getMessage(), ERROR1_VALUE);
}
//Test a runtime exception
@Test(groups = { "unit" })
public void testWithRunProcessException() throws Exception {
doThrow(new RunProcessException("")).when(testObj).update(Matchers.refEq(requestMock), Matchers.refEq(responseMock), Mockito.anyString(), (AcmeBean) Mockito.anyObject());
testObj.handleAddGiftCardToCart(requestMock, responseMock);
assertEquals(1, testObj.getFormExceptions().size());
DropletFormException exception = (DropletFormException) testObj.getFormExceptions().get(0);
Assert.assertEquals(exception.getMessage(), GENERAL_ERROR_KEY);
}
}
显然,上面只是一个框架,非常适合我们开发 FormHandlers 的方式。如果您选择,您还可以为重定向和类似的东西添加验证:
Mockito.verify(responseMock, Mockito.times(1)).sendLocalRedirect(SUCCESS_URL, requestMock);
最终,测试其他人代码的警告仍然适用。