Tag Archives: Unit testing

To autowire or not to autowire (Take 2)

I received an interesting comment on my last article about some capabilities of Mockito that I didn’t know about:

Damien, I don’t agree with you. You can use @Inject on private fields and still be able to unit test easily with Mockito.
For example let’s take a MyClass class with @Injected private fields. In MyClassTest class, I annotate the MyClass field with @InjectMocks, and dependencies with @Mock.
No need to use ugly setters or whatever, it works : mocked dependencies are injected in MyClass.
So when it comes to testing code, I think @Autowired/@Inject on private fields are still suitable. What do you think ?

As a reminder, here is the initial code that I considered a bad practice because of the autowiring on private fields.

@Named
public class AwesomenessFinder {

  @Inject
  private BlogAnalyzer blogAnalyzer;

  @Inject
  private BookmarkService bookmarkService;

  public void checkBlog(String url) {
    if (!bookmarkService.contains(url) && blogAnalyzer.isInteresting(url)) {
      bookmarkService.bookmark(url);
    }
  }
}

It turns out some mocking libraries are totally capable to deal with these dependencies and inject mocks into the private fields. Here is an example of a test class which works very well thanks to Mockito annotations @InjectMocks and @Mock.

@RunWith(MockitoJUnitRunner.class)
public class AwesomenessFinderTest {

  @InjectMocks
  private AwesomenessFinder awesomenessFinder;

  @Mock
  private BookmarkService bookmarkService;

  @Mock
  private BlogAnalyzer blogAnalyzer;

  @Test
  public void checkInterestingBlog_bookmarked() {
    when(bookmarkService.contains(anyString())).thenReturn(true);
    when(blogAnalyzer.isInteresting(anyString())).thenReturn(true);

    String url = "whatever";
    awesomenessFinder.checkBlog(url);

    verify(blogAnalyzer).isInteresting(url);
    verify(bookmarkService).bookmark(url);
  }
}

So autowiring private fields may not be an anti-pattern after all.

I found 3 potential objections to this statement.

  1. With these annotations, we can’t have a different mock for each test method, so you may need to reset your mocks between each test. Apparently, the reset() functionality on Mockito was added for this special case of container-injected mocks. That doesn’t look a big deal, so I would say this objection is a bit weak.
      @Before
      public void setUp() {
        reset(bookmarkService, blogAnalyzer);
      }
    
  2. Not all mocking libraries support injection on private fields and we shouldn’t deliberately restrict our choice of mocking library. For example, JMock and EasyMock don’t support this feature, unlike Mockito and JMockit (as a side note, here is a nice comparison matrix for mocking libraries, possibly biased toward JMockit where it is hosted).

    At first glance, I thought this argument was strong. However it appears to me now that the testing should adapt to the code and not the other way around. For example, I tend to think that a final or static method should be mockable. I know this is debatable and some TDD fanatics would possibly disagree with me, but after all, I think the more power you can get from your mocking library, the better.

  3. My last objection may be the only one standing. The auto injection of mocks solved the problem for testing but what if it’s the application which needs to inject different kinds of dependencies into a class? Here you have no choice but to remove the autowiring from your private fields. I had to deal with this scenario very recently at work, so this can certainly happen, however I find this use case relatively rare. So, when it happens, refactoring a class or two is probably not a big deal.

In conclusion, I have to say I changed my mind and I don’t see any issue with autowiring private fields, except if you’re stuck with a limited mocking library. It may be just a matter of personal preference but thinking about it was a good learning exercice.

To autowire or not to autowire

Since using Spring 2.5, I switched from the XML-based application context to the annotations. Although I find those very useful and huge time savers, I’ve always had the feeling that I was losing something in term of flexibility. In particular the @Autowired annotation – or the standard @Inject – felt to me like the new “new”, increasing the coupling between my classes and making it harder to change implementation when needed.

I still feel that way a bit, but I’ve learned an interesting pattern to limit the problem when it comes to testing my code, i.e. when I want to replace the real implementation of a bean for a mock.

Let’s illustrate with an example. I want to build an application to find interesting stuff on the web for me. I will start with a service which takes a URL and bookmarks it when if it’s a new one which happens to be interesting.

Until recently, I may have coded something like this:

@Named
public class AwesomenessFinder {

  @Inject
  private BlogAnalyzer blogAnalyzer;

  @Inject
  private BookmarkService bookmarkService;

  public void checkBlog(String url) {
    if (!bookmarkService.contains(url) && blogAnalyzer.isInteresting(url)) {
      bookmarkService.bookmark(url);
    }
  }
}

This is bad, can you see why? If not, keep reading, I hope you will learn something useful today.

Because I’m conscientious, I want to create unit tests for this code. Hopefully my algorithm is fine but I want to make sure it won’t bookmark boring blogs or bookmark the same URL twice.

That’s where the problems appear, I want to isolate the AwesomenessFinder from its dependencies. If I was using an XML configuration, I could simply inject a mock implementation in my test context, can I do it with the annotations? Well, yes! There’s a way, with the @Primary annotation. Let’s try creating mock implementations for BlogAnalyzer and BookmarkService.

@Named
@Primary
public class BlogAnalyzerMock implements BlogAnalyzer {

  public boolean isInteresting(String url) {
    return true;
  }
}

@Named
@Primary
public class BookmarkServiceMock implements BookmarkService {

  Set bookmarks = new HashSet();

  public boolean contains(String url) {
    return bookmarks.contains(url);
  }

  public void bookmark(String url) {
    bookmarks.add(url);
  }
}

Because I use Maven and I put those mocks in the test/java directory, the main application won’t see them and will inject the real implementations. On the other hand, the unit tests will see 2 implementations. The @Primary is required to prevent an exception like:

org.springframework.beans.factory.NoSuchBeanDefinitionException:
No unique bean of type [service.BlogAnalyzer] is defined: expected single matching bean
but found 2: [blogAnalyzerMock, blogAnalyzerImpl]

Now, I can test my algorithm:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:application-context.xml")
public class AwesomenessFinderTest {

  @Inject
  private AwesomenessFinder awesomenessFinder;

  @Inject
  private BookmarkService bookmarkService;

  @Test
  public void checkInterestingBlog_bookmarked() {
    String url = "http://www.javaspecialists.eu";
    assertFalse(bookmarkService.contains(url));
    awesomenessFinder.checkBlog(url);
    assertTrue(bookmarkService.contains(url));
  }
}

Not bad, I tested the happy path, an interesting blog gets bookmarked. Now how do I go about testing the other cases. Of course I can add some logic in my mocks to find certain URLs already bookmarked or not interesting, but it would become clunky. And this is a very simple algorithm, imagine how bad it would get to test something more complex.

There is a better way which requires to redesign my class and the way the dependencies are injected. Here is how:

@Named
public class AwesomenessFinder {

  private BlogAnalyzer blogAnalyzer;

  private BookmarkService bookmarkService;

  @Inject
  public AwesomenessFinder(BlogAnalyzer blogAnalyzer, BookmarkService bookmarkService) {
    this.blogAnalyzer = blogAnalyzer;
    this.bookmarkService = bookmarkService;
  }

  public void checkBlog(String url) {
    if (!bookmarkService.contains(url) && blogAnalyzer.isInteresting(url)) {
      bookmarkService.bookmark(url);
    }
  }
}

Note that I still autowire my dependencies with the @Inject annotation, so the callers of my AwesomenessFinder won’t be affected. For example, the following in a client class will still work:

@Inject
private AwesomenessFinder awesomenessFinder;

However, the big difference is that I autowire at the constructor level, which gives me a clean way to inject mock implementations. And, since we’re mocking, let’s use a mocking library. Last year, I wrote a post about mockito where I used ugly setters to inject my mocks. With the technique mentioned here, I don’t need to expose my dependencies anymore, I get a much better encapsulation.

Here is what the updated test case looks like:

public class AwesomenessFinderTest {

  @Test
  public void checkInterestingBlog_bookmarked() {
    BookmarkService bookmarkService = mock(BookmarkService.class);
    when(bookmarkService.contains(anyString())).thenReturn(false);

    BlogAnalyzer blogAnalyzer = mock(BlogAnalyzer.class);
    when(blogAnalyzer.isInteresting(anyString())).thenReturn(true);

    AwesomenessFinder awesomenessFinder = new AwesomenessFinder(blogAnalyzer, bookmarkService);

    String url = "http://www.javaspecialists.eu";
    awesomenessFinder.checkBlog(url);

    verify(bookmarkService).bookmark(url);
  }
}

Note that this is now plain java, there is no need to use Spring to inject the mocks. Also, the definition of those mock is in the same place than their usage which eases the maintenance.

To go a step further, let’s implement other test cases. To avoid code duplication we’ll refactor the test class and introduce some enums to keep the test cases as expressive as possible.

public class AwesomenessFinderTest {

  private enum Knowledge {KNOWN, UNKNOWN};

  private enum Quality {INTERESTING, BORING};

  private enum ExpectedBookmark {STORED, IGNORED}

  private enum ExpectedAnalysis {ANALYZED, SKIPPED}

  @Test
  public void checkInterestingBlog_bookmarked() {
    checkCase(Knowledge.UNKNOWN, Quality.INTERESTING,
        ExpectedBookmark.STORED, ExpectedAnalysis.ANALYZED);
  }

  @Test
  public void checkBoringBlog_ignored() {
    checkCase(Knowledge.UNKNOWN, Quality.BORING,
        ExpectedBookmark.IGNORED, ExpectedAnalysis.ANALYZED);
  }

  @Test
  public void checkKnownBlog_ignored() {
    checkCase(Knowledge.KNOWN, Quality.INTERESTING,
        ExpectedBookmark.IGNORED, ExpectedAnalysis.SKIPPED);
  }

  private void checkCase(Knowledge knowledge, Quality quality,
                         ExpectedBookmark expectedBookmark, ExpectedAnalysis expectedAnalysis) {

    BookmarkService bookmarkService = mock(BookmarkService.class);
    boolean alreadyBookmarked = (knowledge == Knowledge.KNOWN) ? true : false;
    when(bookmarkService.contains(anyString())).thenReturn(alreadyBookmarked);

    BlogAnalyzer blogAnalyzer = mock(BlogAnalyzer.class);
    boolean interesting = (quality ==  Quality.INTERESTING) ? true : false;
    when(blogAnalyzer.isInteresting(anyString())).thenReturn(interesting);

    AwesomenessFinder awesomenessFinder = new AwesomenessFinder(blogAnalyzer, bookmarkService);

    String url = "whatever";
    awesomenessFinder.checkBlog(url);

    if (expectedBookmark == ExpectedBookmark.STORED) {
      verify(bookmarkService).bookmark(url);
    } else {
      verify(bookmarkService, never()).bookmark(url);
    }

    if (expectedAnalysis == ExpectedAnalysis.ANALYZED) {
      verify(blogAnalyzer).isInteresting(url);
    } else {
      verify(blogAnalyzer, never()).isInteresting(url);
    }
  }
}

Last but not least, a nice bonus to the injection by constructor is the capacity to have all the dependencies of a class in the same place (the constructor). If the list of dependencies grow beyond control, you get a very obvious code smell with the size of the constructor. It’s a sign that you certainly have more than one responsibility in your class and you should split it into multiple classes, easier to isolate for unit testing.

Mockito: drink it without moderation

Mockito is probably my favorite java library. It is a popular mocking tool, mostly used to isolate a piece of code during unit-testing.

Let’s go through its main benefits with a simple example. If you already know Mockito you can skip this first section.

1. Mockito in action

Imagine the following requirement: publish a blog post and announce it on twitter with a shortened URL.

We’ll start with some design and decide that the following method will fulfill the requirement:

public class BlogService {
    /**
     * Publish a blog post and announce it on twitter.
     */
    public void publishPost(int postId) {
    }
}

Listing 1 – Designing the interface

Then, we’ll do some TDD and write a test case before coding the implementation. To make it simple, we’ll assume the necessary data is already loaded into the DB with id 1. There are a few options for this to work.

    public void testPublishPost() {
        blogService.publishPost(1);
        post = blogService.getPost(1);
        assertTrue(post.isPublished()); // JUnit assertion
    }

Listing 2 – Writing a test case

Here you notice that we need a database connectivity, that’s totally fine and recommended for unit-testing, unless you suffer of paramockia which is a special form of obsessive–compulsive disorder.

Now let’s implement our method to make this test pass:

    /**
     * Publish a blog post and announce it on twitter.
     */
    public void publishPost(int postId) {
        Post post = blogDao.getPostById(postId);
        post.setPublished(true);
        blogDao.savePost(post);

        String shortUrl = urlShortenerService.shortenUrl(post.getUrl());

        String tweet = "New blog post: " + shortUrl.trim(); // contrived but it will help
        twitterService.post(tweet);
   }

Listing 3 – Implementing

Let’s consider that urlShortenerService and twitterService connect to external systems (bit.ly and twitter.com), that would be annoying to really call these systems during unit-testing. That’s where Mockito will save the day.

We will revisit our test case to mock those 2 services:

    public void testPublishPost() {
        UrlShortener mockShortener = mock(UrlShortener.class);
        blogService.setUrlShortener(mockShortener);

        TwitterService mockTwitter = mock(TwitterService.class);
        blogService.setTwitterService(mockTwitter);

        blogService.publishPost(1);
        post = blogService.getPost(1);
        assertTrue(post.getPublish()); // JUnit assertion
    }

Listing 4 – Mocking

Now we can run our test and … BOOM ! NullPointerException in BlogService (line 11 of Listing 3, I told you trimming would help). By default, Mockito will create a mock object which implements all the non-private methods of the class to mock. But all the methods whose return type is not void, will return null. So we’re trying to trim null.

Let’s revisit our test case and tell Mockito to return something. We’ll also use the verify method to check that the twitterService is called with the argument we expect.

    public void testPublishPost() {
        UrlShortener mockShortener = mock(UrlShortener.class);
        when(mockShortener.shortenUrl(anyString())).thenReturn("short");
        blogService.setUrlShortener(mockShortener);

        TwitterService mockTwitter = mock(TwitterService.class);
        blogService.setTwitterService(mockTwitter);

        blogService.publishPost(1);
        post = blogService.getPost(1);
        assertTrue(post.getPublish()); // JUnit assertion

        verify(mockTwitter).post("New blog post: short");
    }

Listing 5 – Fixing and verifying

Et voila, our test case is now successful. Our business logic has been isolated and unit-tested.

One last note about using Spring to inject mocks, that’s just a no-brainer:

	<bean id="twitterService" class="org.mockito.Mockito" factory-method="mock">
		<constructor-arg value="com.domain.TwitterService" />
	</bean>

Listing 6 – Mocked spring bean

This, with just a few other well documented features, will take you a long way when it comes to mocking and unit-testing.

2. What is so cool about Mockito?

Szczepan Faber, the author of Mockito, has a few things to say on why his tool is well done and conceptually right for unit-testing. I will just focus on a few details which struck me.

Great name

What a great branding! And there’s a great dose of humor on Mockito home page. I love it. Maybe that shouldn’t matter but we, programmers (should I say human beings …), are just kids. We love playing with new toys as long as they’re attractive and fun.

Simplicity: no boilerplate code to write

Mockito is outrageously simple. In fact, I wish I could write something so simple. All the complexity is hidden from the end-user, providing only a simple, yet powerful, API.

This API consists mostly of static methods, that’s an awesome design decision in this case. No need to instantiate unnecessary objects for the single purpose to look object oriented.

Let’s compare this to, let’s say, log4j, which is also a simple and popular library.

private static Logger logger = Logger.getLogger(MyClass.class);

Couldn’t we avoid instantiating these loggers in every class? 99% of the time by putting the current class as constructor argument, which is error-prone.

Generics at their best

Outside of the JDK, Mockito is the smartest usage of generics I’ve ever seen, even including the JDK maybe.

Let’s consider 3 of the main methods we covered in the first section, mock, when and verify. They all use a type parameter, which allows them to return an object of the type needed by the end-user.

For the method mock, it’s obvious, Mockito uses the magic of cglib to create a mock of the specified type, the class to mock.

The method when is not less magical. Here is again the syntax I used earlier:

when(mockShortener.shortenUrl(anyString())).thenReturn("short");

Think about it twice. How would you implement that yourself? Not easy, right?

Our real shortenUrl method was returning a String. The mocked version has to return an object which is a String so it can be used in the code to test. But it also has to be more than a String, so that when used as argument to the when method, it provides a way to modify the behavior of the mock.

The thenReturn method uses a type parameter to ensure the developer pass an object of the same type than the return type of the method “passed” to when  … Simple in the API, impressive under the hood.

The verify method is of the same caliber.

verify(mockTwitter).post("New blog post: short");

It returns an object implementing all the methods of the mocked class, allowing another nice method chaining. But when a method of this object is called, it checks the state of the mock against the given argument to validate it was actually called this way in our tested code.

3. Conclusion

Mockito is a great library. It should be used extensively. But that doesn’t stop here. Mockito is a great source of inspiration for any developer who wants to improve his designing skills.