Is It Bad Practice to Use Reflection in Unit Testing

Is it bad practice to use Reflection in Unit testing?

IMHO Reflection should really only be a last resort, reserved for the special case of unit testing legacy code or an API you can't change. If you are testing your own code, the fact that you need to use Reflection means your design is not testable, so you should fix that instead of resorting to Reflection.

If you need to access private members in your unit tests, it usually means the class in question has an unsuitable interface, and/or tries to do too much. So either its interface should be revised, or some code should be extracted into a separate class, where those problematic methods / field accessors can be made public.

Note that using Reflection in general results in code which, apart from being harder to understand and maintain, is also more fragile. There are a whole set of errors which in the normal case would be detected by the compiler, but with Reflection they crop up as runtime exceptions only.

Update: as @tackline noted, this concerns only using Reflection within one's own test code, not the internals of the testing framework. JUnit (and probably all other similar frameworks) uses reflection to identify and call your test methods - this is a justified and localized use of reflection. It would be difficult or impossible to provide the same features and convenience without using Reflection. OTOH it is completely encapsulated within the framework implementation, so it does not complicate or compromise our own testing code.

Is it bad practice to use reflection to do complex object assertion for a unit test?

IMHO, it is a bad practice because:

  • Reflection code is slow and difficult to write right
  • It is even more difficult to maintain and such code may not be refactor-friendly
  • Reflection is slow, unit tests shall be fast
  • It also doesn't feel right

To me this looks as if you are trying to plug a hole, rather than fix a problem. In order to fix the problem I can suggest to segregate a large and complex class into a set of smaller ones. If you have many properties - group them into individual classes


So that such class

class Foo
{
T1 Prop1 {get; set;}
T2 Prop2 {get; set;}
T3 Prop3 {get; set;}
T4 Prop4 {get; set;}
}

Would become

class Foo
{
T12 Prop12 {get; set;}
T34 Prop34 {get; set;}
}
class T12
{
T1 Prop1 {get; set;}
T2 Prop2 {get; set;}
}
class T34
{
T3 Prop3 {get; set;}
T4 Prop4 {get; set;}
}

Note, that the Foo has now got only one property (that is a "grouped" representation). If you can group the properties in a way, so that any state change would be localised to a specific group - your task becomes much more simplified. You can then assert that a "grouped" property is equal to the expected state.

Is it considered good practice to test presence of annotations using reflection in a unit test?

The basic answer is "Yes - it's fine to check for annotations in unit tests"

Always ask yourself "what am I testing". Unit tests test that the "code is correct" at a class/method level.

You are not really "testing" the code, but you are asserting that coders have correctly annotated certain fields, which in your case is part of asserting that "code is correct", so "yes" - I think it's acceptable to "test" this.

Another option is to make this assertion part of the code style checking phase of your build (if you're doing that) - you would have to write a custom code style to do it, but I feel that would be a more appropriate place to check this. However, that's probably a bit painful to set up, so just do it as a unit test.

How do I test a class that has private methods, fields or inner classes?

If you have somewhat of a legacy Java application, and you're not allowed to change the visibility of your methods, the best way to test private methods is to use reflection.

Internally we're using helpers to get/set private and private static variables as well as invoke private and private static methods. The following patterns will let you do pretty much anything related to the private methods and fields. Of course, you can't change private static final variables through reflection.

Method method = TargetClass.getDeclaredMethod(methodName, argClasses);
method.setAccessible(true);
return method.invoke(targetObject, argObjects);

And for fields:

Field field = TargetClass.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(object, value);


Notes:

  1. TargetClass.getDeclaredMethod(methodName, argClasses) lets you look into private methods. The same thing applies for
    getDeclaredField.
  2. The setAccessible(true) is required to play around with privates.

Testing private variables - always bad practice?

The state of private fields is irrelevant to the correct functioning of the class. You shouldn't be testing private variables.

Test what the class does, not how it does it.

If you want to test that the class sets its internal state correctly, so it behaves in a particular way after that, then call the methods that set the state and test that the behaviour after that is correct.

It doesn't matter if it takes 1000's of tests to ensure that - they are only unit tests, so they'll be fast.

Future coders are at liberty to change the internal workings of a class, as long as the class' contract is upheld.

Is it considered bad practice to use InternalsVisibleTo for Unit Test Code?

No, it is not considered bad practice. There is no other way, if the classes you want to test are internal to your assembly for good reasons. Just not testing them would be a lot worse.



Related Topics



Leave a reply



Submit