Using Mockito for writing ATG test case

2020-04-16 19:31发布

问题:

Does anyone have idea about writing unit test case for ATG using Mockito? I came across following discussions while goggling - Automated unit tests for ATG development and Using PowerMock to obtain the ATG Nucleus in testing results in NPE

But need a help in setting up Nucleus and other dependencies (DAS, DPS, DSS etc.) and a sample test class for droplet using Mockito.

We are using ATG Dust where we have to set all the dependencies. I am wondering if we can replace ATG Dust completely with Mockito. Here is the example how we are writing the test cases -

  1. A Base class for setting Nucleus -
package com.ebiz.market.support;

import java.io.File;
import java.util.Arrays;
import atg.nucleus.NucleusTestUtils;
import atg.test.AtgDustCase;
import atg.test.util.FileUtil;

public class BaseTestCase extends AtgDustCase {
public atg.nucleus.Nucleus mNucleus = null;
private final String ATGHOME="C://ATG/ATG9.4//home";
private final String ATGHOMEPROPERTY = "atg.dynamo.home";

protected void setUp() throws Exception {
super.setUp();
String dynamoHome = System.getProperty(ATGHOMEPROPERTY);
if(dynamoHome == null)
System.setProperty(ATGHOMEPROPERTY, ATGHOME);
File configpath = NucleusTestUtils.getConfigpath(this.getClass(), this.getClass().getName(), true);
FileUtil.copyDirectory("src/test/resources/config/test/", configpath.getAbsolutePath(), Arrays.asList(new String [] {".svn"}));
copyConfigurationFiles(new String[]{"config"}, configpath.getAbsolutePath(), ".svn");
}

public File getConfigPath() {
  return NucleusTestUtils.getConfigpath(this.getClass(), this.getClass().getName(), true);
}
}
  1. Writing the test case by extending the base class -
public class BizDropletTest extends BaseTestCase {
private BizDroplet bizDroplet;

@Before
public void setUp() throws Exception {
super.setUp();
mNucleus = NucleusTestUtils.startNucleusWithModules(new String[] { "DSS", "DPS", "DAFEAR" }, this.getClass(),
this.getClass().getName(), "com/ebiz/market/support/droplet/BizDroplet");
autoSuggestDroplet = (AutoSuggestDroplet) mNucleus.resolveName("com/ebiz/market/support/droplet/BizDroplet");
try {
bizDroplet.doStartService();
} catch (ServiceException e) {
fail(e.getMessage());
}
}

/**
Other methods
*/
}

So, how Mockito can handle these? Again, for me the target is to replace ATG Dust with Mockito completely because ATG Dust take lot of time in running tests due to huge dependencies.

Thanks.

回答1:

Using Mockito you don't setup Nucleus or other dependencies (unless you need it). You simply mock the objects that you need to use.

Consider a simple class ProductUrlDroplet that retrieves a product from the repository and then outputs a url based on this. The service method would look something like this:

public void service(DynamoHttpServletRequest pRequest, DynamoHttpServletResponse pResponse) throws ServletException, IOException {
    Object product = pRequest.getObjectParameter(PRODUCT_ID);

    RepositoryItem productItem = (RepositoryItem) product;
    String generatedUrl = generateProductUrl(pRequest, productItem.getRepositoryId());

    pRequest.setParameter(PRODUCT_URL_ID, generatedUrl);
    pRequest.serviceParameter(OPARAM_OUTPUT, pRequest, pResponse);
}

private String generateProductUrl(DynamoHttpServletRequest request, String productId) {

    HttpServletRequest originatingRequest = (HttpServletRequest) request.resolveName("/OriginatingRequest");
    String contextroot = originatingRequest.getContextPath();

    return contextroot + "/browse/product.jsp?productId=" + productId;
}

A simple test class for this will then be:

public class ProductUrlDropletTest {

@InjectMocks private ProductUrlDroplet testObj;
@Mock private DynamoHttpServletRequest requestMock;
@Mock private DynamoHttpServletResponse responseMock;
@Mock private RepositoryItem productRepositoryItemMock;

@BeforeMethod(groups = { "unit" })
public void setup() throws Exception {

    testObj = new ProductUrlDroplet();
    MockitoAnnotations.initMocks(this);
    Mockito.when(productRepositoryItemMock.getRepositoryId()).thenReturn("50302372");
}

@Test(groups = { "unit" })
public void testProductURL() throws Exception {
    Mockito.when(requestMock.getObjectParameter(ProductUrlDroplet.PRODUCT_ID)).thenReturn(productRepositoryItemMock);

    testObj.service(requestMock, responseMock);
    ArgumentCaptor<String> argumentProductURL = ArgumentCaptor.forClass(String.class);
    Mockito.verify(requestMock).setParameter(Matchers.eq(ProductUrlDroplet.PRODUCT_URL_ID), argumentProductURL.capture());
    Assert.assertTrue(argumentProductURL.getValue().equals("/browse/product.jsp?productId=50302372"));
}

}   

The key components are that you need to initialise the class you want to test (testObj). You then simply construct the response for each of the input parameters of the objects you are going to use (in this case productRepositoryItemMock represents the RepositoryItem and productRepositoryItemMock.getRepositoryId() returns a String that you can then test against later).

You will also notice that this test only validates the service method and not the individual methods. How you do it is up to you but generally I've been focused on testing my service and handleXXX methods in the formhandlers and droplets.

Testing the XXXManager, XXXUtil and XXXService classes will all have their own tests and should be 'mocked' into the droplets and formhandlers. For these I would write tests for each method though.

PowerMockito only really comes into the picture when you need to mock static methods and classes and the documentation does enough to explain that.



标签: mockito atg