Sean U
Sean U

Reputation: 6850

Unit tests in same class (with conditional compilation)?

I'm aware of (and agree with) the usual arguments for placing unit tests in a separate assembly. However, of late I've been experiencing some situations where I really want to be testing private methods. The behind-the-scenes logic in question is complex enough that testing the public and internal interfaces doesn't quite get the job done. The testing against the class's public interface feels overwrought, and I see several spots where a few tests against privates would get the job done more simply and effectively.

In the past I've tackled these kinds of situations by making the stuff I need to test protected, and creating a subclass that I can use to get at it in the test framework. But that doesn't work so well on classes that should be sealed. Not to mention bloating the test framework with all that scaffolding.

So I'm thinking of doing this instead: Place some tests in the class, where they can get at the private members. But keep them out of the production code using '#if DEBUG`.

Does this seem like a good idea?

Upvotes: 7

Views: 1185

Answers (3)

k.m
k.m

Reputation: 31484

Before anybody asks...

The solution to OP's problem is to properly incorporate IoC with DI and eliminate the need of testing private method altogether (as Joel Martinez noted). As it's been mentioned multiple times, unit testing private members is not the way to go.

However, sometimes you just can't change the code (legacy systems, risk of breaking changes - you name it) nor you can use tools that allow private members testing (like Typemock, which is paid product). For such cases, you can either not test at all, or cut corners. Which I believe is situation OP's facing.


Leaving private methods testing discussion aside...

Remember you can use reflection to access and invoke private members.

In my opinion, placing conditional debugs in the class itself is rather bad idea - it adds noise (as in, something unrelated) to the class code. Sure, it will be gone in release, but you (and possibly other programmers) will have to deal with it on the daily basics.

I realize your idea might sound good on paper - simple test wrapped with conditional debug. But in reality, tests quickly turn out to use extra variables (those will also have to be placed in the class code), some utility (extra references, custom types), testing frameworks (even more references) and what not. This all will have to be somehow connected to the class code. Put that all together, and you quickly end up with an unmaintanable monster.

Are you sure you want to deal with that? Especially considering that throwing together simple reflection-based utility is probably not that hard.

Upvotes: 9

Adam Houldsworth
Adam Houldsworth

Reputation: 64547

If you need to test this method independently of the public API of the class, then it sounds like a candidate for being removed from the class itself.

You could say the class is dependent on the private method (as is arguably evident by the need to test it separately from the class public API).

If this dependency cannot be satisfied through testing the public API of the type alone then have the class instead delegate this dependency to another type. You can either instantiate this type internally or have this type injected / resolved.

This new type can then have its own unit tests, as it's public API will be expressing what was previously a private method.

Upvotes: 4

Joel Martinez
Joel Martinez

Reputation: 47809

Everything you're referring to can be solved with just two concepts: Single Responsibility Principle, and Dependency Injection. It definitely sounds like you need to simplify your classes. Mind you, that doesn't mean the class must offer less value, it just means that the internals need to be simpler and some functionality may have to be delegated to others.

Upvotes: 7

Related Questions