How to test non-public method?

How to test non-public method?

When we want to add test for legacy system or we do TAD (test after development), we will find it’s hard to add test for public method, so the workaround is testing non-public method, but this workaround is good? And how can we do if we must use this workaround?

No. 1 Don’t test non-public method.

Why we need write test? One of reasons is improving code quality. What’s the good code? It’s clean, following the basic OO principle. The most important OO principle is encapsulation. When we begin testing non-public method, no matter what way we use (see the following), we actually violate the encapsulation. I think we can “google” million pages to explain the side effects for the violation of encapsulation, or just think about this: if we are a consumer of a class, more interfaces the class has, happier we are, but if we are an own of a class (we work in the class), more interface the class has, more difficulties we have. So as an OO programmer, don’t violate encapsulation as possible as we can, that’s the OO basic principle.

So what we can do? We don’t write test if we think it’s impossible or hard to test the public method (class interface)? NO! I like a word. “If you think it’s impossible to add test, it only means your design is bad.” We need refactor code before adding test. Maybe you will challenge how can we do code refactoring without tests, please see “How can we refactor code without unit tests”. Normally, when we think it’s hard to test a public method, there could be some smells, like “Long method”, “Large Class”. So we need do code refactoring to remove these code smells to add test.

If we don’t have enough time to do code refactoring, or we don’t master refactoring skill without unit testing, we can use the following ways to add test, but they are not recommended ways, only can be used in the short term.

No. 2 Make method be protected or internal

Make method be protected, and then create a new class which inherits from the tested class. Create a public method, call the protected method in the base class.

Make the method be internal, sign test project. Add InternalsVisibleTo with the PublicKey of test project in production project.

What the difference between protected and internal?

Personally, I prefer making method be protected instead of internal; especially when the production is not API assembly. When we work in assembly, I think, most of time, we always work in assembly, it’s actually become public for the internal method. Remember what we should really case is encapsulation. Maybe you will think more information will be exposed if use protected instead of internal from the perspective of assemble, yes, you are right, but you probably should ask yourself the assembly you are working is API production? We also know make method be protected is not good choice. Inheritance is powerful in OO, but inheritance also has side efforts – inheritance is more coupling than composition, that’s why we should choose composition instead of inheritance as possible as we can when we do OO programing.

So if there is only a little sub-class in non-API assembly, prefer making method be protected instead of internal. And another option is using internal class instead of internal method.

No.3 Use reflection

Some tools, like Visual Studio Testing tool provide “fancy” function to let you test everything, these tools just use reflection. But I think it should be our last option. Personally I don’t want to use it forever.

Conclusion

Be careful when we change private method with protected or internal, we shouldn’t violate encapsulation due to test. Test helps us improve code quality instead of messing code. Try to follow TDD to implement software, there will no need to test non-public method.

posted on 2013-03-23 14:02  没Ready  阅读(784)  评论(2编辑  收藏  举报

导航