Question

I have created a new class which extends a 3rd party abstract class. The new class calls methods in the abstract class. The problem I have is when trying to write the unit test, I'm not sure how to write a test as I would not know the exact details the 3rd party class requires.

The AbstractDecoratorMapper below is a SiteMesh specific class which I have to extend for SiteMesh to work correctly. As far as I can tell from the documentation I can't use composition.

public final class PartnerDecoratorMapper extends AbstractDecoratorMapper {

    @Override
    public void init(Config config, Properties properties, DecoratorMapper parent) throws InstantiationException {
        super.init(config, properties, parent);
    }

    @Override
    public Decorator getDecorator(HttpServletRequest request, Page page) {
        if (super.getDecorator(request, page).getName().equalsIgnoreCase("default")) {
            return getNamedDecorator(request, "externalPartnerDefault");
        }
        return super.getDecorator(request, page);
    }
}

I use JMock if there is anything this tool can do to help.

Was it helpful?

Solution

There are two things you might be asking. I'll try to answer both.

Possible Question 1) How do I test my Additional Functionality?

Possible Question 2) How do I test the the combined functionality is appropriate?

Let me start with Question1.

I would suggest a simple peel. There is a video of the technique here: http://www.youtube.com/watch?v=p0tILwRZH5Q (the video is c# but basically identical in java)

which would mean you would have the following code afterwards

@Override
public Decorator getDecorator(HttpServletRequest request, Page page) {
    Decorator d = super.getDecorator(request, page);
    return getResolvedDecorator(d, d.getName(), request);

}
public Decorator getResolvedDecorator(Decorator current, String name, HttpServletRequest request) {
    if (name.equalsIgnoreCase("default")) {
        return getNamedDecorator(request, "externalPartnerDefault");
    }
    return current;
}

Now you can test this with a call like

assertEquals(expected, new PartnerDecoratorMapper().getResolvedDecorator(null, "default", MockHttpServletRequest);

I would suggest possibly removing data from HttpServletRequest as well, to make the testing & intent clearer.

Note: this has the added performance benefit that the call to super.getDecorator() only occurs once, since the result is cached.

Additional Note: It is also worth noting that the override of init() is unneeded, and doesn't actually do anything.

Question 2: This is a harder question, as you don't state what the desired behavior is. I am assuming this is a factory pattern, so most likely it would work in some manner like

| http request quality 1 | Page quality 1| Expected Decorator | | /mypath/mypage | status = foo | MyDecorator |

(I have no idea what this above chart should contain or look like) Once you have this behavior then the test to ensure it would be rather straight forward.

Happy Testing, Llewellyn

OTHER TIPS

You don't need to know details from 3rd party libs... you just need to mock them returning something you expect from them.

In the case you are inheriting it you could setup the class as it will be used on production and invoke the methods that should be invoked in regular uses. All that you need to check is if the result is as you expect. (you don't need to know exactly how the 3rd party classes works on the test).

In order to check if all code you implemented was executed you can use a plugin to check the coverage like eclemma - http://www.eclemma.org/ )

With JMock, you can't to the best of my knowledge mock calls to a superclass of the class under test.

The answers to this related question may be useful, but the main answer is to switch to a mocking framework (JMockit is suggested) that does support this.

as I would not know the exact details the 3rd party class requires

Testing, of any kind, compares what something actually does with what it ought to do. You can not test until you know what something ought to do: "what the 3rd part class requires".

And how can you make any reasonable attempt to write your derived class if you do not know what the base class requires? What does the API documentation for the class you are extending say?

Is the problem perhaps that there is no such API documentation, or it is uninformative? It might be that, although the class is not final, it is not really intended to be used as a base class. Either of those indicate a poorly designed API, and suggest you should not bother using it

Or is the critical difficulty that you do not know the exact details? That might be a flaw in your approach: typically you can not and must not make assumptions about exact details. Your code should conform to the documented API, and you should not assume anything that is not stated in the documented API. That can mean that you can not know when your Template Methods might be called or what the values will be passed to them. If the base class communicates with your Template Methods by passing objects that are declared to implement an interface or a non-final class (that is, their type but not their class is specified), you can not know what class those objects will have.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top