Unit test helper methods?

2019-03-15 02:17发布

I have classes which previously had massive methods so I subdivided the work of this method into 'helper' methods.

These helper methods are declared private to enforce encapsulation - however I want to unit test the big public methods. Is it good to unit test the helper methods too as if one of them fail the public method that calls it will also fail, and this way we can identify why it failed?

Also in order to test these using a mock object I would need to change their visibility from private to protected, is this desirable?

9条回答
老娘就宠你
2楼-- · 2019-03-15 03:00

This smells like you have the wrong problem. What you've described is akin to creating a sub-"unit test", which leads me to believe that your unit tests are really testing a unit after all.

Which is not a criticism of what you are trying to do: going from "where we are today" to "somewhere else that's measurably better" is a winning move. However, it is a suggestion that you step back a bit to evaluate where you are - understanding how your current situation differs from some Platonic ideal could help to show new possibilities.

There are plenty of suggestions here about scoping your helper methods. Another possibility would be to review the implementation to determine if there are helper classes lurking in your current implementation. Creating a new class and a suite of tests to exercise it is always acceptable.

Note that this approach insulates you from the refactoring: you can change the implementation without changing your test suite (because the unit tests for the helper object continue to pass even when the helper object is no longer part of your production implementation), and you get a clean packaging of the implementation and the tests for it (usecase: you decide that bozo-sort is the wrong implementation, and should no longer be used. If the bozo-sort implementation is isolated, then you simply remove it and its tests. But when the tests of the bozo-sort implementation are tangled with all of the other tests, there's more thinking involved).

It may also help to review why you have unit tests for your code. If one of the reasons is "to make refactoring safe", then you don't want to be writing tests that lock you into an implementation.

查看更多
唯我独甜
3楼-- · 2019-03-15 03:01

As Don and Dror say, making the methods public so you can create unit tests for them breaks encapsulation. You then tie yourself to a particular implementation. By making them public, you declare to the world that these methods are part of the published interface and therefore their specifications are locked.

Personally, I'd go for a more pragmatic solution: Keep them private and don't write unit tests. If you get to a case where a public method fails and you can't figure out why but you think it might be a problem in one of your private methods, then temporarily make them public, write the unit test, debug, and when you're done, make them private again and comment out the unit test.

查看更多
Rolldiameter
4楼-- · 2019-03-15 03:10

This is one of those cases where I would say go ahead and break the rules.

If you were designing the class from scratch, you definitely don't want helper methods to be unit tested on their own, but... since you are refactoring an existing class, it's acceptable to bend the rules in order to make sure you don't break anything.

Making them protected will let you test the helpers themselves, to make sure they still have the behavior you are expecting as you pull the logic out of the big hairball method, as well as allow you to stub them out and return fixed responses so that you can make sure the big method you are refactoring behaves as expected for certain results of the helper methods.

But you're not done yet at that point. Splitting the method up isn't really getting to the root of your problem. Now that you have the method broken up and a set of (slightly unorthodox) tests that show you exactly what all of the logic does, you are in a good position to re-examine the whole class and try to figure out why the method was so big in the first place. Most likely your whole class also needs to be broken up into smaller units with discrete responsibilities that will then be easier to test without bending any rules.

查看更多
登录 后发表回答