How to Create Unit Tests for Controllers

Extensibility
Extensibility covers the mechanisms by which you, as the user or developer, can extend the functionality of the Teradata Database, for example with the use of User Defined Functions, or UDFs.
Teradata Employee

How to Create Unit Tests for Controllers

Writing quality unit tests for portlet controllers is important in the development process because doing so results in sound code. Unit testing quickly reveals flaws and regressions in code that has been written, allowing code to be more easily maintained.

Unit testing of Teradata Viewpoint code is dependent on two essential elements:

  1. TestNG: The unit testing is driven by the TestNG framework, an alternative to JUnit. TestNG is a powerful framework that allows advanced unit test configuration through annotations.

  2. EasyMock: EasyMock allows the creation of mock interfaces. This allows the unit testing of objects in isolation. EasyMock also supports mock classes with an available extension.

Setup

Once the unit tests necessary for the class have been conceptualized, setup of the unit tests and the required objects is the first order of business. Although it is not mandatory, all unit test classes written should contain both setUp() and tearDown() functions. These functions perform essential tasks:

  • setUp(): Initializes the common objects and functionality that will be used by all unit tests for this class.
  • tearDown(): Destroys the common objects and functionality that were created by the setUp() function.

  • import static org.testng.Assert.*;

    import org.testng.annotations.AfterTest;
    import org.testng.annotations.BeforeTest;
    import org.testng.annotations.Test;

    /**
    * The unit tests for the MyClass class.
    */
    @Test
    public class MyControllerTest
    {
    private MyController cls;

    /**
    * Check that the constructor allocated an object.
    */
    public void testFunction()
    {
    assertNotNull(cls);
    }

    /**
    * Set up my object.
    */
    @BeforeTest(alwaysRun = true)
    public void setUp()
    {
    // Instantiate an instance of MyController
    cls = new MyController();
    }

    /**
    * Tear down my object.
    */
    @AfterTest(alwaysRun = true)
    public void tearDown()
    {
    cls = null;
    }
    }

Mock Interfaces with EasyMock

If you are using the Business Delegate pattern to separate your presentation and business layers, then you will be mocking interfaces for your unit testing. EasyMock provides a quick and easy solution to implement the mock objects, define their expected behaviors and verify them for inconsistent results. There are several mock object calls that are important to constructing a mock:

  • expect(): Programs the mock to expect a call to the specified function and defines the behavior of the function call.
  • replay(): Switches the mock from programming mode to testing mode.
  • reset(): Restores the mock to its initial state, and returns it to programming mode.
  • verify(): Verifies that the expected behavior of the mock occurred.
import static org.easymock.EasyMock.*;
import static org.testng.Assert.*;

import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;

/**
* The unit tests for the MyClass class.
*/
@Test
public class MyControllerTest
{
private MyController cls;
// A mock interface
private MyMockInterface mMI;

/**
* Check that the constructor allocated an object.
*/
public void testFunction()
{
assertNotNull(cls);
}

/**
* Test the MyMockInterface object.
*/
public void testMyMockInterface()
{
assertNotNull(mMI);
// Reset the mock for declarations
reset(mMI);
// Expect only one call to myReturnFunction() and return the value 100
expect(mMI.myReturnFunction()).andReturn(100).once();
mMI.myNonReturnFunction();
// Set the call expectation of a single call to myNonReturnFunction() with no return
// value
expectLastCall().once();
// Prepare the mock for testing
replay(mMI);

// Call myReturnFunction() as expected
int x = mMI.myReturnFunction();
// Call myNonReturnFunction() as expected
mMI.myNonReturnFunction();

// Verify that the proper behaviors occurred during the testing of the mock
verify(mMI);
// Assert that the correct value was returned by the mock
assertEquals(x, 100);
}

/**
* Set up my objects.
*/
@BeforeTest(alwaysRun = true)
public void setUp()
{
// Instantiate an instance of MyController
cls = new MyController();
// Create a MyMockInterface mock object
mMI = createMock(MyMockInterface.class);
}

/**
* Tear down my objects.
*/
@AfterTest(alwaysRun = true)
public void tearDown()
{
cls = null;
mMI = null;
}
}

Mock Classes with EasyMock

Mocking a class is nearly identical to mocking an interface. The declarations and functionality are the same; the only difference is the import used. You must import org.easymock.classextension.EasyMock.* instead of org.easymock.EasyMock.*.

Using the MockControllerContext

The MockControllerContext class is a mock used for unit testing a Teradata Viewpoint controller that implements the controller interface or extends the FormControllerBase class. This allows the controller to be tested while being isolated from the controller base that has been extended. For example, assume that the MyController class implements the controller interface. You can use the MockControllerContext class as a parameter when invoking its methods:

import static org.easymock.EasyMock.*;
import static org.testng.Assert.*;

import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;

import com.teradata.portlets.mvc.MockControllerContext;

/**
* The unit tests for the MyClass class.
*/
@Test
public class MyControllerTest
{
// MyController implements the Controller interface
private MyController cls;
// Our MockControllerContext instance
private MockControllerContext context;

/**
* Check that the constructor allocated an object.
*/
public void testFunction()
{
assertNotNull(cls);
}

public void testMyController()
{
// Call the summary view of the test controller
cls.summary(context);
// Check that the mock has the correct view name
assertEquals(context.getViewName(), "summary");
}

/**
* Set up my objects.
*/
@BeforeTest(alwaysRun = true)
public void setUp()
{
// Instantiate an instance of MyController
cls = new MyController();
// Instantiate an instance of MockViewpointControllerSupport
context = new MockControllerContext();
}

/**
* Tear down my objects.
*/
@AfterTest(alwaysRun = true)
public void tearDown()
{
cls = null;
context = null;
}
}