Sunday, August 12, 2012

Testing private methods using singleton methods

I generally use rspec for Ruby unit tests. However, at first glance, it seems that good test coverage is in conflict with good encapsulation. Specifically, private methods cannot be directly tested without some additional thought.

One strategy that is widely advocated is to only test private methods indirectly, through their use by public methods. While perfectly valid, this approach may let use cases slip through the cracks. For example, it may not always be feasible to use the public methods to test all the uses of the private method that one may want to test. This is actually the reason for unit tests in the first place, because not all use cases and exceptions can be uncovered by higher-level interaction (i.e., using the application, integration tests, etc.)

Another strategy is to put all the private methods in a module and include them. However, this means your code gets scattered in multiple places, and that module may not have any other use outside of the one class.

Enter instance_eval

With instance_eval, one can directly call the private method as follows:

obj.instance_eval{ my_private_method }.should 

VoilĂ .

Perhaps one rule of thumb is to use instance_eval sparingly, and only in unit tests (never in integration tests). 

For more discussion on this topic (and a debate about whether private methods should be tested), see this StackOverflow post.

Kevin


No comments: