Search code examples
javaunit-testingjunitmockingjunit4

How To Java Unit Test a Complex Class


I'm experiencing a difficult time on figuring out how to approach a problem with unit testing. I have little to no 'unit testing' experience. I am trying to change the classUnderTest only if absolutely necessary with minimal changes.

I am using JUnit 4, and I am willing to try to use Mockito, JMockit or any other libraries that would help with efficient and effectively unit testing. I am using JDBC for the database.

Problem:

Within the classUnderTest, I'm accessing a static database.

SpecializedDao specializedDao = SpecializedDao.getSpecializedDao();
ObjectX objectResult = specializedDao.currentObjectXByTimestamp(x, x, x, x, x, x);

and I am trying to use do unit test cases with a valid config, and an invalid config. What is the correct way to approach this problem.

Some possible solutions I have researched are:

  1. Somehow passing in, or 'injecting' a fake ObjectXResult of class ObjectX
  2. Mock a database (if even possible with static db reference, use separate unit-test servlet that references a fake SpecializedDao class?)
  3. Use Mockito with injectMocks, spy, when(methodcallwithparameters) thenReturn result, or some other implementation Mockito provides.
  4. Open to any other solution.

Problem:

Within the classUnderTest, I am using another complex processing class2 that does a lot of the work like so:

result = class2.execute(x, x, x, x, x, x);

class2 does processing stuff and returns a result ENUM or some exceptions. How do I handle this with keeping the scope of this specific Unit Test on classUnderTest. class2 accesses the database, and does a lot of the work which is why it is its own class but I think the final three test cases are dependent upon the processing to thoroughly test classUnderTest.

Thanks for bearing with me, I tried to make the question with as much clarity as possible.


Solution

  • My recommendation, if you care about developing good, useful tests, is to not mock the database, or other complex classes your code may interact with.

    Instead, think of the specific business scenarios that your code under test is meant to deliver, and write a realistic (ie, without replacing real classes/components with cheap - and often incorrect - imitations of them) and meaningful (from the point of view of real-world requirements) test for each scenario.

    That said, if you still want to mock that DAO class, it can be done as follows using JMockit:

    @Test
    public void exampleTest(@Mocked SpecializedDao mockDao) {
        ObjectX objectResult = new ObjectX();
    
        new Expectations() {{
            mockDao.currentObjectXByTimestamp(anyX, anyY, anyZ); result = objectResult;
        }};
    
    
        // Call the SUT.
    }
    

    (anyX, etc. are not the actual JMockit argument matching fields, of course - the real ones are anyInt, anyString, any, etc.)