Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using "friend"-declarations for unit testing. Bad idea?

[Of course, the question is not restricted to a specific "friend" implementation, feel free though to point out implementation specifics if relevant]

Reading through the unanswered questions, I stumbled upon the InternalsVisibleTo attribute:

Specifies that types that are ordinarily visible only within the current assembly are visible to another assembly.

The C# Programming Guide on MSDN has a section Friend Assemblies describing how to use the attribute to allow the use of internal methods and types to another assembly.

I'm wondering whether it would be a Good Idea to use this to create a "hidden" interface for instrumenting a library for use by the unit testing assembly. It seems to increase coupling massively in both directions (testing code in the production assembly, intimate internal knowledge about the production assembly in testing code), but on the other hand it might help in creating fine-grained tests without cluttering the public interface.

What is your experience with using friend declarations when testing? Was it your Silver Bullet, or did it start the Death March?

like image 221
David Schmitt Avatar asked Nov 04 '08 07:11

David Schmitt


People also ask

Is it bad to unit test private methods?

I would recommend disabling unit tests that target private methods. They are a code coupling, and will burden future refactoring work, or even sometimes get in the way of feature addition or modification.

What makes a bad unit test?

Likewise, a poor unit test can arise due to different attributes or practices, which should be avoided and may include: Non-deterministic factors in the code-base are problematic, since they are difficult to test; for example, time as an authentication factor in code can fail due to different time zones.

What is the major disadvantage of unit testing?

Limitations of Unit Testing Unit testing cannot detect integration or interfacing issues between two modules. It cannot catch complex errors in the system ranging from multiple modules. It cannot test non-functional attributes like usability, scalability, the overall performance of the system, etc.


2 Answers

I've made extensive use of this technique - it means that my unit tests can test aspects of the code library that aren't visible to normal consumers.

While using [InternalsVisibleTo] does increase coupling, I believe the (minor) increase is well worth the gains.

My unit tests are already tightly coupled to the code under test - though I try to write tests that assure specific outcomes, not specific implementations, by accessing things not visible to regular consumers, I do somewhat constrain the implementation.

Going the other way, the coupling is minimal - in having the [InternalsVisibleTo] attribute on the code assembly, and in marking some things as internal instead of private (or protected internal instead of protected).

(Note that I'm ignoring here any design changes that are provoked by the use of Unit Testing, which is a whole other discussion.)

The [InternalsVisibleTo] attribute requires strong naming your assemblies. If you're not doing this already, you may find this a bit burdensome as a strongly named assembly may only depend on other strongly named assemblies, which may end up with you needing to alter several assemblies.

Getting the attribute right can be a bit fiddly, as it needs to include the public key of your test assembly. IDesign have a useful Friend Assembly tool that creates the attribute on your clipboard, ready for pasting. Recommended.

like image 69
Bevan Avatar answered Oct 10 '22 06:10

Bevan


It's the only use I've ever personally applied to InternalsVisibleTo - and it's been very, very handy indeed.

I don't view unit tests as black box testing - they're already coupled to the implementation to some extent. Being able to test internal types and methods allows a much tighter focus (smaller units).

like image 26
Jon Skeet Avatar answered Oct 10 '22 06:10

Jon Skeet