Tom is a passionate Java/JEE developer working remotely from home located in Poland. He is a big fan of Apache Wicket, clean code, testing and methods with names that actually say something. In his free time he blogs, tweets and organizes Confitura, the biggest Java conference in Poland. Privately husband, father and dog owner, he likes to watch and play football (soccer if you're from USA). Tomasz is a DZone MVB and is not an employee of DZone and has posted 15 posts at DZone. You can read more from them at their website. View Full User Profile

Practical Unit Testing with TestNG and Mockito – Review

08.01.2012
| 19613 views |
  • submit to reddit

Practical Unit Testing with TestNG and Mockito” (website) covers a wide spectrum of knowledge about testing in the Java environment using the aforementioned libraries. But if you prefer JUnit over TestNG or PowerMock over Mockito, it is still a valid and a very good source of information about proper and painless testing. But of course, TestNG and Mockito users will be able to get most of this title. Below you can read some of my thoughts after reading this book.

Quick look at content

Tomek Kaczanowski, author of this book, starts with describing some basic concepts needed to understand testing and classification of tests. He introduces definitions of SUT- System Under Test and DOC – Depended On Component. Then after this really short theoretical chapter we start diving deeper into gradually more and more complex testing cases.

We start with simple class without any dependencies, easy to understand and easy to test. Then we could feel rhythm of Test-Driven Development with TestNG, learn how to use mocks, stubs and spiess from Mockito, employ matchers and checking assertions using FEST. Example after example, we are introduced to more complex features of those libraries. but luckily for those not using TestNG with Mockito, each chapter is full of general tips and suggestions abuot testing methodology, how to approach testing properly and finally how and what to test.

Then we could learn about customizing TestNG using listeners and reporters, organizing test classes into packages and modules, organizing code in test methods (famous BDD given-when-then trio).

Last chapters are devoted completely to most general things: maintaining tests, deciding which parts of your code base are worth testing, checking quality of your tests with static analysis tools (PMD, Coberturda and so on).

My opinion

I am using TestNG for over a year (after switching from JUnit), Mockito for more than three years so I am quite familiar with those tools. And for people with similar or greater experience this book will not surprise on each single page. This will or, at least in my opinion, will happen for those less familiar with testing and using TestNG and Mockito. For them this book is a totally must read as it gently introduces reader to world of proper unit testing using best toolbos available in Java world.

I am far from saying that for more experienced developers this book is not a good way to spend their time. It’s still good, I learned many interesting features of described libraries but what is most important, my knowledge about testing is now more complete and more ordered. Reading all this stuff helped me to put many stuff into “proper shelves” in my mind. And that’s very good.

To sum up: The less experienced in testing you are, the more you will get from this book. And for people who are testing and using TestNG and Mockito for over a eight or more years: this book is probably not for you.

If you place yourself in the middle, Practical Unit Testing with TestNG and Mockito is still a very good choice as it will help you to systematize all the stuff you already know and meanwhile you will surely learn something new about tools and, worth to note, about general efficient and painless approach to testing your code.

My takeaways

Below some of my personal notes about things I didn’t know or didn’t use often before reading this book.

Enriching html test reports

TestNG has a nice class org.testng.Reporter that allows developer to add some information to html reports

@Test
public void testSomething() {
    Reporter.log("This is so soo important, please read it!");
 
    //test something
}

And after running such tests in html report we will see something like presenten on the screenshot below:

and additionally all such messages are gathered in one, separate report.

 

Clear separation between important and dummy test data

Let’s suppose that we are testing following method

@Test
public void loadByAgeRange() {
    service.loadClientBy(1, 20, 40, null);
}

and compare it with listing below:

@Test
public void loadByAgeRange() {
    int ageFrom = 20;
    int ageTo = 40;
 
    service.loadClientBy(ANY_TYPE, ageFrom, ageTo, ANY_REGION);
}

Isn’t it much clearer? We replace dummy data with constants indicating which part is important and what parameters are not critical in this method.

Mocks auto injection

Mockito allows us to automatically inject all mock into object we are going to test:

@InjectMocks private ObjectUnderTest object = new ObjectUnderTest();

Of course it has some limitations (see JavaDocs) but it’s good to know that such feature is already in Mockito.

Make-it-easy - A tiny framework that makes it easy to write Test Data Builders in Java

This small project will help you to create builders for your test cases easily. More can be found on its wiki, but below simple use case showing how it looks:

Person nat = make(a(Person, with(name, "Tomek"), with(age, 28)));

Partial Mocking

If there is a method we want to test but at the same time there is another method in tested object that want to mock, it is possible to do that by usinf Mockito spy():

@Test
public void testCaluculationSummary() {
    TestedObject object = spy(new TestedObject());
    when(object.executeHeavyCalculations()).thenReturn("resultString");
 
    int result = object.getCalculationsSummary();
 
    assertThat(result).isEqualTo(10);
}

Testing and capturing method arguments

Mockito gives us another very useful feature, ability to check what arguments were passed to methods using ArgumentCaptor:

@Test
public void testArgument() {
    // ...
    CustomerService customerService = mock(CustomerService.class);
    ArgumentCaptor argument = ArgumentCaptor.forClass(Customer.class);
    verify(customerService).saveCustomer(argument.capture());
 
    testedObject.executeSomeMethodCallingSaveCustomer()
 
    assertThat(argument.getValue()).isEqualTo(expectedCustomer);
}

 

 

 

 

Published at DZone with permission of Tomasz Dziurko, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Rogerio Liesenfeld replied on Thu, 2012/08/02 - 7:40am

I found three errors in this review:

1) "Mocks auto injection": Normally, Mockito (1.9.0+) should be allowed to instantiate a field annotated with @InjectMocks, rather than doing it explicitly in test code.

2) "Partial Mocking": Generally, using "when(...).thenReturn(...)" (or "thenThrow" or "thenAnswer") with an "spy" may not work, as it will always execute the real method on the spied object. Instead, the alternative methods "doReturn", "doThrow", and "doAnswer" should be used.

3) "Testing and capturing method arguments": The example test, as shown, will not work since it calls "verify(...)" and "argument.capture()" *before* exercising the code under test. Both calls must come after that.

There are other more (dare I say) "modern" mocking tools available for Java, namely Unitils Mock (with about the same power as Mockito but without the API inconsistencies) and JMockit (which I develop, and perhaps properly described as having the power of Mockito + PowerMock with a smaller API).

Tomasz Dziurko replied on Thu, 2012/08/02 - 11:29am in response to: Rogerio Liesenfeld

Rogerio, thank you for you comments but some of your points are not valid.

Re 1) Code you are claiming to be an error is completely valid. Developer might instantiate object annotated by @InjectMocks or might leave it to Mockito. It depends on situation and mainly on number and types of constructors this class has and we want to use in a given test method or class

Re 2)  You are writing "may not work" which is a bit vague. Using spy and doReturn is in line with Mockito documentation and, what is more important, it just works, see example at http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html#13. Methods that were not stubbed will call real object and real implementation will be executed, but those which we stubbed will return specified (mocked) result.

Re 3) In this case you are correct. Verify and argument.capture should be called AFTER executing code under test. Thanks for pointing that out :)

Those two tools you have mentioned look interesting, I will try to use them in one of my sandbox projects, thanks for sharing :)

 

 

 

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.