-1

I am new to Mockito as a concept. Can you please help me understand using Mockito for formhandlers in ATG. Some examples will be appreciated.

Charles
  • 50,943
  • 13
  • 104
  • 142
user2879266
  • 59
  • 1
  • 5
  • What have you tried? Which FormHandler are you trying to Mock. It is not too different from Mocking a Droplet and there are a few examples on SO for that. – radimpe Oct 29 '13 at 05:47

3 Answers3

0

There is a good answer (related to ATG) for other similar question: using-mockito-for-writing-atg-test-case. Please review if it includes what you need.

Many of ATG-specific components (and form handlers particularly) are known to be "less testable" (in comparison to components developed using TDD/BDD approach), b/c design of OOTB components (including reference application) doesn't always adhere to the principle of having "Low Coupling and High Cohesion"

But still the generic approach is applicable for writing unit-tests for all ATG components.

Community
  • 1
  • 1
0

Below is a framework we've used for testing ATG FormHandlers with Mockito. Obviously you'll need to put in all the proper bits of the test but this should get you started.

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

    }

Obviously the above is just a framework that fit in nicely with the way in which we developed our FormHandlers. You can also add validation for redirects and stuff like that if you choose:

Mockito.verify(responseMock, Mockito.times(1)).sendLocalRedirect(SUCCESS_URL, requestMock);

Ultimately the caveats of testing other people's code still applies.

radimpe
  • 3,197
  • 2
  • 27
  • 46
0

Here's what I do when I unit test a form handler (at least until I manage to release a major update for AtgDust). Note that I don't use wildcard imports, so I'm not sure if this causes any namespace conflicts.

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

The basic idea is to set up custom behavior for mocks/stubs using when() on the mock object method invocation to return some test value or throw an exception, then verify() mock objects were invoked an exact number of times (in the default case, once), and do any assertions on data that's been changed in the form handler. Essentially, you'll want to use when() to emulate any sort of method calls that need to return other mock objects. When do you need to do this? The easiest way to tell is when you get NPEs or other runtime exceptions due to working with nulls, zeros, empty strings, etc.

In an integration test, ideally, you'd be able to use a sort of in-between mock/test servlet that pretends to work like a full application server that performs minimal request/session/global scope management. This is a good use for Arquillian as far as I know, but I haven't gotten around to trying that out yet.

Matt
  • 637
  • 3
  • 10