Unit test is to test the logic of a class with its dependencies mocked. To do that, here are the best practices I used when I test classes in different layers of my project.
Use TestNG
TestNG is a replacement for JUnit. It “fixes†many of the issues with JUnit, and we will use it as our primary testing framework.
Get it work with Eclipse:
- Select menu Help->Software Updates->Find and Install.
- Select Search for New Features to Install
- New remote site.
- Enter and use TestNG for the description URL http://beust.com/eclipse in the URL
- Make sure the check box next to http://beust.com/eclipse is checked and click Next.
- Write your test under src/test/java with the same package name as the corresponding class you are trying to test. Name your test XXXTest. XXX = the class name of the subject class you are testing.
- To run this class, Right click it in Package Explorer and select Run As-> TestNG test. Your test should run successfully.
import org.testng.annotations.AfterSuite;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.Test;
import static org.testng.AssertJUnit.*;public class CalculatorTest {
 private Calculator calculator;
Â
 @BeforeSuite protected void setUp() throws Exception {
  calculator = new Calculator();
 } @AfterSuite protected void tearDown() throws Exception {
  calculator = null;
 } @Test() public void testAdd() {
  int results = calculator.add(1, 1);
  assertEquals(2, results);
 Â
 } @Test() public void testMultiply() {
  int results = calculator.multiply(1, 1);
  assertEquals(1, results);
 }}
TestNGÂ has the following advantages over JUnit (Detail here)
- Test class doesn’t extend any unit testing framework code like ”extends TestCase” and force you to name your test methods in a certain way. Instead, it uses annotation to achieve the goal. (eg. @BeforeClass/@AfterClass, @BeforeMethod/@AfterMethod, @BeforeSuite/@AfterSuite, @BeforeTest/@AfterTest, @Test, @DataProvider, @Factory).
- For TestNG configuration, edit testng.xml file.
- TestNG doesn’t reinstantiate your class for each test method as JUnit does. No repeat setUp and tearDown method calls. And you no longer need static field to carry state across test methods.
- TestNG introduces test group.
@Test (groups = {“functest”})
- Support dependency testing - if method A test is failed, there is no point to test B.
@Test (dependsOnMethods = {“verifyLogIn”})
- Test expected exception
@Test (expectedExceptions = NumberFormatException.class})
- Fail and rerun – TestNG will write the failed test case in testng-failed.xml and next time just rerun the failed one – save time!
- Parametric testing – In JUnit, if you had 10 different parameter combinations to test a method, you would be forced to write 10 test cases. In TestNG, you can define one test case and then push your desired parameter patterns (for example) into TestNG’s suite files. However, I still prefer to use different method names to capture the corner cases as different inputs may give different behaviors for a method.
- Test thread safety. The power of TestNG comes from its support of thread safety test!!
@Test(invocationCount=1000, threadPoolSize=10, timeOut=10000)
public void cachePut()
{
    m_cache.put(“foo”, “bar”);
}
Test Spring MVC Controller
Traditionally, testing J2EE Web components has been a more difficult task than testing standalone Java objects because Web components must run in some form of the server platform and they are coupled to the specifics of the HTTP-based Web interaction. To make it easy, Spring provides a mock implementation for each key interface from the Web side. Here I just list out the most common use ones:
- MockHttpServletRequest – You most likely will find a use for this class in every single one of your unit tests. It is the mock implementation of the most frequently used interface in J2EE Web applications: HttpServletRequest.
- MockHttpServletResponse – Use this object for mock implementations of the HttpServletResponse interface.
- MockHttpSession – This is another frequently used mock object. (This article will review use of this class for session-bound processing later.)
- MockServletConfig – This is a mock implementation of the ServletConfig interface. Unit testing some Web components, such as the ones the Struts framework supplies, requires you to set the ServletConfig and ServletContext interfaces implemented by MockServletContext.
On the other hand, you can make your unit test spring-aware via:
- AbstractDependencyInjectionSpringContextTests – This is a superclass for tests, depending on the Spring context.
- AbstractSpringContextTests – This is a superclass for all JUnit test cases using a Spring context, and as such, it is not intended to be used directly. You will most likely end up using either AbstractDependencyInjectionSpringContextTests or subclasses of AbstractTransactionalSpringContextTests.
- AbstractTransactionalSpringContextTests – This is a superclass for all the tests that should occur in a transaction but that will normally roll the transaction back upon the completion of each test. You need to override onSetUpInTransaction and onTearDownInTransaction to manually initiate and/or commit the transaction (for instance, to flush the Hibernate session).
- AbstractTransactionalDataSourceSpringContextTests – This is a subclass of AbstractTransactionalSpringContextTests that is geared towards the use of the Spring’s JDBC-based jdbcTemplate convenience class.
Follow the link below to find out how to test the Spring MVC classes.
http://www.devx.com/Java/Article/30067/0/page/2
Test DAO Layer
Before writing any tests for the Data Access Layer, we should consider the following things:
- Do we want to hit the database at all or should we mock out the database communication API?
- If we have to hit the database, do we want to hit the real production version of the database or do we want to hit an in-memory lightweight database?
The answer is that it is too much of work to test just the interaction between dao and database. And It is much more meaningful to have the test hits the database to exercise the schema, stored procedure and more. For the 2nd question above, I would have each developer has his own db instance running locally and the database should be the same as the one we use in production. This way we can avoid sql compatibility issue related to using in-memory database like hsql instead. On top of it, if you can make sure the schema version is in sync with your code during test automatically, it will eliminate lots of headache down the road.
http://www.buunguyen.net/blog/unit-testing-the-data-access-layer.html
Write integration test in Service Layer
1 Comments.