Unit Testing – Making Public Methods Virtual to Ease Testability

object-orientedunit testing

I have been looking around for some practices to write testable code and gathered the following:

• Public methods virtual if not using interfaces — makes mocking easier
• Dependency injection — makes mocking easier
• Smaller, more targeted, choesive methods — tests are more focused, easier to write
• Avoidance of static classes
• Avoid singletons, except where necessary
• Avoid sealed classes

I am not sure if I get the point of the first one, making public methods virtual, should I really do that?

Best Answer

Public methods virtual if not using interfaces -- makes mocking easier

Do not focus on mocks. Mocks are a valuable testing tool, but every time you create a mock, you are testing your code against an artificial environment, rather than the one it'll face in production. So minimise your use of mocks. To that end, marking methods as virtual really is a test tool of last resort. Overriding a method in order to test can often cause more problems than it solves (the tests all too easily break when changes are made to the way the two methods interact in the real code for example). Instead, use interfaces in the first place for when you do need to mock.

Dependency injection -- makes mocking easier

No! Stop fixating on mocking. Dependency injection helps reduce coupling between parts of your code, making both maintenance and testing far easier. Mocking is only made easier (if needed) by referencing those injected dependencies via interfaces.

Smaller, more targeted, choesive methods -- tests are more focused, easier to write

Smaller, more cohesive methods have many advantages. They tend to be far simpler to understand for a start. They can indeed also be easier to test. This one is definitely good advice.

Avoidance of static classes

Static classes only need to be avoided when their methods have side effects (access or modify global state, external resources like the file system, databases etc). If the methods are pure, ie rely on only their inputs and constants to derive a deterministic result, then make them static.

[Addendum, as a nod to something I learned from RobertHarvey recently, beware using static for methods that take a long time to execute. Unit tests should be fast and may need to mock slow methods, so don't make those methods static]

Avoid singletons, except where necessary

Avoid (in fact, never use) the singleton pattern. It's a glorified global variable. It's an anti-pattern. It's never ever necessary to use it.

Single instances of classes, injected into those parts of the code that need access absolutely should be used though. Please don't end up creating two copies of a class just to avoid being accused of using a singleton for example.

Avoid sealed classes

If a class is badly designed, doesn't use an interface and has virtual methods so they can be overridden by tests, then this holds true. But you don't want that; you want well designed classes that are accessible via interfaces and that do not contain virtual methods. At which point you can seal all of them. I do.