Search

Ted Vinke's Blog

Java, Groovy and stuff

Category

Testing

The Librarian: Introduction to Test-Driven Development

This will be a series of articles revolving around unit testing where I will work through examples and exploring various aspects of the craft. This is the first installment.

The code associated with this article can be found on GitHub. Future and past installments can be found in The Librarian Archive.

TDDI will try to implement a few requirements for a Library module with books and memberships, extending whatever code we have in a test-driven style (“TDD”) as we go along. I share a few thoughts about the process, show some refactorings and give a few hints for using the IDE.

The level of this article is for junior developers who want to expand their testing horizon.

There’s plenty of information out there which describes what TDD or Test-Driven Development is, the red-green-refactor cycle etc so I won’t delve into too much introductory detail here. See the references at the end for more background-information.

Instead, just get started!
Continue reading “The Librarian: Introduction to Test-Driven Development”

So If You’re Using Tag Libraries for Your View Models You Have To Test Them, Right?

In a previous post I introduced thinking about (visual) components and used a Task Browser as an example of an user interface “component” .

grails-task-overview-main-screen-wireframe

I explained that using

  • View Model(s) e.g. plain-old Groovy objects (POGOs) holding the related data e.g. a class TaskBrowser
  • Tag Libraries (LayoutTagLib) and tags (def taskBrowser) to render the associated HTML (views/layouts/components/_taskBrowser.gsp) to the page

allows for more maintainable and testable code.

Let’s put our money where our mouth is and see how one could test the used tag library. Continue reading “So If You’re Using Tag Libraries for Your View Models You Have To Test Them, Right?”

How to mock configuration in a Grails unit- or integration test?

Sometimes you may need to mock Grails (application) configuration in an unit or integration test.

E.g. you want to test code which normally would access the property jmxEnabled from the following configuration block:

In Grails 2 in Config.groovy

someService {
  jmxEnabled = true
}

or Grails 3 in application.yml

someService:
  jmxEnabled: true

Here’s are the most simple options for a Grails 2.4.x or Grails 3.0.x Spock unit- or integration test.

Unit test

In your unit test you have an implicit config reference you can use. Either in a specific test or in a setup() initialize it with a value you want to test with.

@TestFor(MyService)
class MyServiceSpec extends Specification {

  def setup() {
    config.someService.jmxEnabled = false
  }

This is actually the getConfig() method in the GrailsUnitTestMixin class which Grails automatically “mixes” into your unit test class.

Integration test

In your integration test, inject grailsApplication as a bean and access the configuration through its config property – just as you would in the actual production code.

class MyServiceIntegrationSpec extends Specification {

  def grailsApplication
  ...

  def setup() {
    grailsApplication.config.someService.jmxEnabled = false
  }

Written for Grails 2.4+ and Grails 3.0.x.

Mockito: Why You Should Not Use InjectMocks Annotation to Autowire Fields

People like the way how Mockito is able to mock Spring’s auto-wired fields with the @InjectMocks annotation. When I read this post of Lubos Krnac last week, I thought I should explain why I think the use of InjectMocks is a bad signal and how you should avoid it. Hint: it’s about visibility.

Let’s say we have a PlannerServiceImpl which delegates to a PlannerClient. Uses Spring for auto-wiring all together; there’s no constructor, but Spring is able to use field injection.

@Service
public class PlannerServiceImpl implements PlannerService {
    private static final Logger LOG = LoggerFactory.getLogger(PlannerServiceImpl.class);

    @Autowired
    private PlannerClient plannerClient;

    @Override
    public Long createWeddingPlan() {
        try {
            CreateWeddingPlanResponse response = plannerClient.createWeddingPlan();
            return convert(response).getId();
        } catch (Exception e) {
            LOG.error("Unable to create wedding plan", e);
            return null;
        }
    }

An associated test could look like:

@RunWith(MockitoJUnitRunner.class)
public class PlannerServiceImplTest {

    @Mock
    private PlannerClient plannerClient;

    @InjectMocks
    private final PlannerServiceImpl plannerService = new PlannerServiceImpl();

    @Test
    public void testCreateWeddingPlanWhenClientReturnsUndefinedResponseThenNullIsReturned() throws Exception {
        when(plannerClient.createWeddingPlan()).thenReturn(null);

        final Long actual = plannerService.createWeddingPlan();

        assertThat(actual, is(nullValue()));
    }

The org.mockito.InjectMocks annotation can be seen as an equivalent of Spring’s own dependency injection. The Javadoc states:

Mockito will try to inject mocks only either by constructor injection, setter injection, or property injection in order and as described below. If any of the following strategy fail, then Mockito won’t report failure; i.e. you will have to provide dependencies yourself.

(Whoever would design this to fail silently at all?)

So what if someone decides to create a new dependency, say an AuditService and upgrades a bunch of services by adding it as an additional property, also marked as @Autowired?

@Service
public class PlannerServiceImpl implements PlannerService {
    private static final Logger LOG = LoggerFactory.getLogger(PlannerServiceImpl.class);

    @Autowired
    private PlannerClient plannerClient;

    @Autowired
    private AuditService auditService;

    @Override
    public Long createWeddingPlan() {
        try {
            CreateWeddingPlanResponse response = plannerClient.createWeddingPlan();
            auditService.addEntry("Wedding plan created.");
            return convert(response).getId();
        }

The test will fail, probably on a NullPointerException on a missing AuditService – and it is not visible why. InjectMocks will fail silently and there’s no indication the test needs this. Did I already ask whoever would design something like this to fail silently?

If you’re doing TDD or not (and we are able to change the test first) – clients of this code don’t know about an additional dependency, because it’s completely hidden. You shouldn’t use InjectMocks to deal with injecting private fields (err..or at all) , because this kind of Dependency Injection is evil – and signals you should change your design.

There, I said it.

Fix #1: Solve your design and make your dependencies visible.

Create a constructor. Pass along the PlannerClient.

@Service
public class PlannerServiceImpl implements PlannerService {
    private static final Logger LOG = LoggerFactory.getLogger(PlannerServiceImpl.class);

    private final PlannerClient plannerClient;

    @Autowired
    public PlannerServiceImpl(final PlannerClient plannerClient) {
        this.plannerClient = plannerClient;
    }

Now, when there are more dependencies needed, they’re clearly in sight because the constructor says so. So don’t go creating a bunch of setters now – they still don’t force you to pass along your required dependencies!

@Service
public class PlannerServiceImpl implements PlannerService {
    private static final Logger LOG = LoggerFactory.getLogger(PlannerServiceImpl.class);

    private final PlannerClient plannerClient;

    private final AuditService auditService;

    @Autowired
    PlannerServiceImpl(PlannerClient plannerClient, AuditService auditService) {
        this.plannerClient = plannerClient;
        this.auditService = auditService;
    }

The test itself won’t compile any more (luckily, because of the way we’ve been instantiating the field as plannerService = new PlannerServiceImpl()!) as soon as e.g. the AuditService is added to the constructor. So it’s time to..

Fix #2: Get rid of @InjectMocks

There’s no need to use @InjectMocks anymore. Instead instantiate the class-under-test properly in a @Before-annotated method – where it belongs, passing along all needed dependencies.

@RunWith(MockitoJUnitRunner.class)
public class PlannerServiceImplTest {

@Mock
private PlannerClient plannerClient;

@Mock
private AuditService auditService;

private PlannerServiceImpl plannerService;

@Before
void setUp() {
    plannerService = new PlannerServiceImpl(plannerClient, auditService);
}

Luckily, Lubos – which I mentioned earlier – completely independently came to the same conclusion in the mean time 🙂

Create a free website or blog at WordPress.com.

Up ↑