Using “friend”-declarations for unit testing. Bad idea?

拜拜、爱过 提交于 2019-11-30 06:36:45
Bevan

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.

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).

Jay Bazuzi

I think using InternalsVisibleToAttribute to enable unit testing is perfectly reasonable. My "unit" in "unit testing" is a class, and that includes internal classes, so I want to test them. I don't want to unit test private methods, though.

I don't think creating a special, private interface just for tests is a good idea. One of the values of unit testing is that it gives you a chance to think about the interface to your class from the point of view of a consumer of that class; providing a back door takes that benefit away.

My preference, however, is to put my unit tests in the same assembly as my production code. It doesn't usually affect my customer, but it does simplify things for me, so I do it. When I do, it makes the InternalsVisibleTo question go away.

In fact, Unit Testing is the only use that I've been able to bring myself to use the InternalsVisibleToAttribute for. With this you can implement a large portion of your 'private' methods as internal instead to expose them to the unit testing framework for more invasive testing of class-internal invariants.

I've had great success with this technique. If nothing else it helps you approach that mythical 100% code coverage goal by letting you invoke private methods in situations that are otherwise inaccessible.

Jeff

I think another legitimate use case comes in when you have used separate assemblies when bringing together legacy C++ code with newer C# code.

We've taken the C++ assemblies, converted them to C++/CLI, and then implement newer code in C#. When we do this, we would still use "internal" for the classes/methods in C# that aren't really public, and then make these available to the legacy code as friend assemblies.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!