6

In my application I have quite a few service classes that act as a façade and delegate most calls to one or more underlying manager classes. I've read very different opinions on how to test such façades. Some people say it's not necessary to test them at all, others say one should test whether the integration is working.

I've implemented two test methods for the delegating method below. One test is checking whether the underlying manager method has been called exactly once, the other test checks whether the passed data is equal (or in this case: the same).

@Stateless
public class ApplicationService {

    @Inject
    ApplicationManager applicationManager;

    public List<Application> getApplicationsList() {
        return applicationManager.getApplications();
    }

    ...
}

@RunWith(CdiRunner.class)
public class ApplicationServiceTest {

    @Produces
    @ProducesAlternative
    @Mock
    ApplicationManager manager;

    @Inject
    ApplicationService service;

    @Test
    public void testGetApplicationsListCalled() {
        service.getApplicationsList();
        verify(manager, times(1)).getApplications();
    }

    @Test
    public void testGetApplicationsListPassthrough() {
        ArrayList<Application> given = new ArrayList<>();
        given.add(new Application("app1", "desc1", BusinessCriticality.C1));
        given.add(new Application("app2", "desc2", BusinessCriticality.C1));
        when(manager.getApplications()).thenReturn(given);

        List<Application> resulting = service.getApplicationsList();

        Assert.assertEquals(given, resulting);
        Assert.assertEquals(2, resulting.size());
    }
}

I'd love to hear opinions from experienced devs on whether testing such methods makes sense and if it does, which method of testing is better.

2
  • I would say the real problem here is having those "facades" in the first place. A proper "Facade" (as described in the Design Patterns/GoF book) exists to provide a simpler, smaller API to a pre-existing external API which is more complex than what the application needs. When it's just a do-nothing class containing methods that simply delegate to another application class, then it's an anti-pattern. Eliminate it and then the issue of testing the facade will also go away.
    – Rogério
    Commented Nov 1, 2016 at 18:58
  • Hi @Rogério and thanks for the answer. Feel free to make it a real answer (instead of comment). I agree in that most classes in my layers system do nothing but passing things around, but I found that to be the only way of creating reliable packages and interfaces. For example, my *Manager classes contain lots of logic and many methods meant for other managers, whereas the *Service classes are a filtered view on the managers. My view classes only access the *Service classes. This layer-based abstraction gives me more flexibility than Java interfaces.
    – Hugo G
    Commented Nov 2, 2016 at 9:08

2 Answers 2

3

You have to distiguish between whitebox tests and blackbox tests.

As blackbox tests do not know, how a component behaves, you have no clue if the called method is only a delegate or complex logic. As well you abstract from knowing which resources will be accessed so any potential resource has to be available a test runtime (unless you know to mock some resources). As you do not know a lot of things, you have assume the worst. So you should test every method. Black box test tend to be integration tests.

As the code provided is code under your control you know what the code is doing whitebox tests are appropriate. So you know if a method is only a delegate. These methods should not be tested as these tests express nothing. What you should do is to test if the object which methods are delegated to is properly initialized (null reference exceptions). If you now test the method of the delegate-object you are done because you know delegation can be process as the object is available and the delegated method works fine.

Unit tests for a method begin with at least TWO statements as with a second statement you maybe introduce first interesting thing to test: call order.

The next structure you should be aware of are conditional statements. You should try to refactor methods to have only one level of conditions. The problem with conditions is they may lead to a test case explosion if you have too much levels and conditional elements. Beside test possibility: To have small methods is always a good idea.

2
  • Thanks for the detailed answer. So basically you say I should write a test for my service that checks whether the manager was properly injected?
    – Hugo G
    Commented Nov 2, 2016 at 9:31
  • White boxing testing for facades can have tests for error handling also. Tests to make sure that the facade is handling all the exception that can be thrown by the service client.
    – IThinkSo
    Commented Oct 16, 2017 at 10:19
0

From best practices perspective keep unit tests (JUnits + mock) separate from integration tests. You want unit tests to run independent of any system resources (barring any test data resource files). You can either mock service.getApplicationsList() or implement a factory pattern that will return service.getApplicationListFromTestImpl() in your first method to work with test data.

Integration tests should cover all system resources.

11
  • 2
    Sorry, but this answer doesn't help me in any way. The test above does run independently of any system resources and it doesn't involve more than one class, so I'd say it's a unit test. However, this is not my question. You say, I should mock the service method getApplicationsList() - what do I gain by mocking a method I want to test? Same goes for the factory. I don't want to change the implementation except where necessary. I don't feel like introducing a factory improves the testability of this class.
    – Hugo G
    Commented Nov 2, 2016 at 9:15
  • service.getApplicationsList() is making a service call - correct? If so, then these are not unit tests and these are integration tests. The ideal way to unit test getApplicationList() is to go to the core implementation that retrieves the lists. If lists are coming from db, etc., write a test data provider class - so that the unit test gets test data, perform whatever logic/checks it needs to, and then returns the list to the external caller.
    – donlys
    Commented Nov 2, 2016 at 13:29
  • If you are writing integration tests - then technically you don't need to have the second test to compare the list size - all you really want to test is that it is returning some data and so confirming that integration is working.
    – donlys
    Commented Nov 2, 2016 at 13:30
  • service.getApplicationsList() is what the view code uses (backing beans to be precise). The service is part of a layer that sits between the view related code and the lower-level managers. If I get you correctly, you say I shouldn't test that service at all, but only the underlying manager, right?
    – Hugo G
    Commented Nov 2, 2016 at 13:48
  • A unit test tests a method. Since you are not unit testing getApplicationsList() - yes - you just need one IT.
    – donlys
    Commented Nov 2, 2016 at 14:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.