【问题标题】:Mockito implemetation for formhandlers in ATGATG 中表单处理程序的 Mockito 实现
【发布时间】:2013-10-28 12:42:55
【问题描述】:

我是 Mockito 的新手。你能帮我理解在 ATG 中使用 Mockito 处理表单处理程序吗?一些例子将不胜感激。

【问题讨论】:

  • 你试过什么?您要模拟哪个 FormHandler。它与 Mocking a Droplet 并没有太大的不同,并且有一些关于 SO 的示例。

标签: mockito atg


【解决方案1】:

对于其他类似问题有一个很好的答案(与 ATG 相关):using-mockito-for-writing-atg-test-case。请检查它是否包含您需要的内容。

众所周知,许多 ATG 特定组件(尤其是表单处理程序)“可测试性较低”(与使用 TDD/BDD 方法开发的组件相比),OOTB 组件(包括参考应用程序)的 b/c 设计不t始终坚持有"Low Coupling and High Cohesion"的原则

但通用方法仍然适用于为所有 ATG 组件编写单元测试。

【讨论】:

    【解决方案2】:

    下面是我们使用 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);
    

    最终,测试其他人代码的注意事项仍然适用。

    【讨论】:

      【解决方案3】:

      这是我对表单处理程序进行单元测试时所做的事情(至少在我设法发布 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() 模拟对象被调用准确的次数(在默认情况下,一次),并对表单处理程序中已更改的数据执行任何断言。本质上,您将希望使用 when() 来模拟需要返回其他模拟对象的任何类型的方法调用。你什么时候需要这样做?最简单的判断方法是当您因使用空值、零、空字符串等而导致 NPE 或其他运行时异常时。

      在理想情况下,在集成测试中,您可以使用一种介于模拟/测试之间的 servlet,它假装像一个完整的应用程序服务器一样工作,执行最少的请求/会话/全局范围管理。据我所知,这对 Arquillian 很有用,但我还没有开始尝试。

      【讨论】:

        猜你喜欢
        • 2014-12-22
        • 2014-12-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-05-14
        • 1970-01-01
        相关资源
        最近更新 更多