I’m writing a messaging layer that should handle communication with a third party API. The API has a bunch of classes that cannot be easily (if at all) instantiated in a test harness. I decided to wrap each class that I need in my unit tests with an adapter/wrapper and expose the members I need through this adapter class. Often I need to expose the wrapped type as well which I do by exposing it as an object. I have also provided an interface for for each or the adapter classes to be able to use them with a mocking framework. This way I can substitute the classes in test for whatever I need. The downside is that I have a bunch of adapter classes that so far server no other reason but testing. For me this is a good reason by itself but others may find this not enough. Possibly, when I write an implementation for another third party vendor’s API, I may be able to reuse much of my code and only provide the adapters specific to the vendor’s API. However, this is a bit of a long shot and I’m not actually sure it will work.
What do you think? Is this approach viable or am I writing unnecessary code that serves no real purpose? Let me say that I do want to write unit tests for my messaging layer and I do now know how to do it otherwise.
Edit:
As suggested in some of the answers, I do use IoC/DI. That’s the main reason why I have the interfaces for the adapter classes.
Edit:
I don’t like exposing the wrapped objects either. The reason I do it is that some wrapped types need to access other wrapped types. E.g. I have a third-party MessageProducer that needs a third-party Message object to send it. I have wrapped both of these types in Adapters and use the adapters wherever I can. Unfortunately in some cases it’s not possible.
Instead of a bunch of interfaces and classes. Make a bunch of interfaces and only one implementation class for all the interfaces.
I imagine this third party doesn’t follow the Tell don’t ask policy. It probably ejects a lot of state.
Try to keep all the third-party state in the implementation class. Don’t let it leak pass the interfaces.
Remember that the interfaces will be roles not objects.
You write: Often I need to expose the wrapped type as well which I do by exposing it as an object. This is way wrong!
The best example that I can think of is the data pattern Data Gateway, except you will be using Third-Party Gateway.
Don’t ever expose anything from the third-party. if you need a data object of some sort. convert third-party object to your own object and use it.
[EDIT]
The comment about 3rdParty message producers requiring a 3rdParty message is exactly what I’m talking about wrapping. If you take a data gateway that uses a relational database. Lets say we want to find an item in the database. My Model doesn’t create an SQL then query the database. Instead I use an interface role: itemGateway.find(index). Now in find method is where we would generate the SQL and do the connection/query/close on the database. So in your unit tests you can mock the gateway when testing for find in your model. This is what I would call combat training. The real hard part now comes from the operational programming shit (The Matrix). You could then test just through the gateway. This would be the way I test. My gateway would need about three to four objects (the fourth would be configuration to get tables if your schema is complex). The other three role objects would be SQLBuilder, DataReader, and DB. These all can be mocked so that you could verify the interactions of the interface call. So in the example you would need all three objects.
In an example of itemGateway.save(data), you would only need the SQLBuilder and database.