views:

61

answers:

4

Hi,

It is often said that interfaces making mocking and unit testing an easier process. How do interfaces help with this?

Thanks

A: 

It is the nature of the Interfaces to provide many implementations, thus enable mocking.

Especially in integration testing you are able to give your version of a dependency system mock-up (eg. web-service). Instead of actually calling a dependent system or even a module, or a complicated and difficult to instantiate type, you can provide a simplest interface implementation that will provide results needed for the unit test to complete correctly.

In addition to that, when you use in unit testing an actual dependent types (call it BigGraph) hiding complicated object model behind them, you are in fact do integration testing not unit testing. Your test can easily brake if there is a bug in any of the dependent types (BigGraph), not the type you're testing, thus not unit-testing. Using mock-ups reduce risk of that happening.

Iv'e seen many continuous integration systems show dosens of errors for one bug introduction, when they should show up one, at most couple. All because of to complicated object models, and incorrectly written unit-test - not using mock-ups.

Today mocking frameworks are more sophisticated (bytecode modification, etc.) than the old days so sometimes interfaces or even virtual methods aren't always needed, but nerveless interfaces enable.

Interfaces will not help if your object model is to much complicated and cluttered, (eg. your interface relays heavily on other types/interfaces) then implementing/mocking all this is a pain.

WooYek
+2  A: 

If you are not bound to a concrete implementation, you can switch behaviors behind an interface.

If your classes implement interfaces, behaviors can be mocked.

For example you do not need to spam all your customers in your database to test if your mail notification algorithm works. You will create a mock for your IMailSender interface and only count the number of emails sent. Then you will test the actual implementation that is actually sending the emails on a single email address and you know that the whole notification process works.

In this particular example, the test uses a mock implementing IMailSender that only counts the emails sent and your actual production code will use an implementation implementing IMailSender that actually sends the emails via SMTP server.

Marek
+2  A: 

If you have several objects that have a different implementation but offer the same methods to the outside sharing the same interfaces enables you to write one unit test and run it against all the implementations.

If you have a class that says posts stuff to web back end and then retrieves an answer unit testing that would be problematic, because a failed internet connection could let your test fail. Therefore you define an interface for this class and then you can write a second implementation that logs the stuff that should be send and delivers the correct answer. This way you can test the classes that work with the answer from the back end without relying on a internet connection during test run time.

Janusz
+1  A: 

If you have a class, you can have lots of dependencies like

  • Insane constructors (lots of arguments, or it needs some other class which needs a third class which needs a fourth class which needs to a valid database connection)

  • To use the class in any way, you must initialize it correctly (for example, you must pass it some other objects that must be valid, too)

  • The class has a state. This state can change during the test for some reason.

  • The class might have or use static fields

These dependencies are usually irrelevant during many of your tests and you'd rather not have to deal with them.

With an interface, you can create a simple mock class which just implements the few methods you need. Most mocking frameworks have built-in support for this. "Implement" here usually means "return a fixed value". This way, you can quickly build the environment that the class under test needs.

So for example, if your class needs to read records from a database, you can instead mock a ResultSet which just returns the rows. Hence you don't have to have a real database, you don't need to create a connection (which is slow and can fail for many reasons), you don't have to care about the data in the database (so you don't have to delete/drop tables and fill them again with test data), etc.

Aaron Digulla