2

I was thinking about using reflection for unit tests where 2 objects will be compared for equality and GetProperties() and GetFields() methods will be used extensively. However, I know that the performance impact will be very significant. In fact, couple of my coworkers used reflection for a deep copy of some sourceobject to targetobject. The code is absolutely elegant, beautiful and does exactly what it's supposed to do. The problem is they had to scrap it because it was really slow. So, is all lost when it comes to using reflection in unit tests or is there a way to implement it without a ridiculous performance hit? Thanks a lot in advance.

UkraineTrain
  • 469
  • 1
  • 9
  • 21

5 Answers5

2

You may take a look at HyperDescriptor which could speed things up compared to reflection.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
1

Check out AutoFixture's Likeness. It does exactly what you describe above. Then you can test whether you find the performance acceptable.

See this other question for an example of usage: How to Compare two objects in unit test?

Community
  • 1
  • 1
Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
  • Sorry, but this not exactly what I need. I need my code to dig into 2 objects filled with valid values, comparing their properties and fields. – UkraineTrain Apr 26 '11 at 17:39
  • Sorry for the confusion,but I've meant that I don't need autogenerated values, because I need to compare against values coming from the database, XML file or what have you. – UkraineTrain Apr 26 '11 at 18:58
  • 1
    Yes, I understand that. Likeness is the inverse part of AutoFixture. Instead of creating objects, it compares them. It does come in the same package, though. Did you read the last link in my answer? – Mark Seemann Apr 26 '11 at 19:03
  • Yes, I've read the second link. It still didn't convince me how I could compare two objects property-by-property with some of them being several levels deep and then generate an error message for the properties that are not equal using Assert.AreEqual method. – UkraineTrain Apr 26 '11 at 19:30
  • 1
    In 2.1 (currently in beta) there's a ShouldEqual method that gives you a more detailed error message. However, by default it doesn't compare 'several levels deep'. If you stop to think about it, how can it? How would it decide when to stop? When there are no more properties? In this case, it would do a deep comparison on string as well, equaling strings if they have same Length - that wouldn't make sense. – Mark Seemann Apr 26 '11 at 19:43
1

However, I know that the performance impact will be very significant.

If you don't have measurements, you don't know that. You might suspect it...

The simplest way to avoid reflection costs is to use reflection to generate the unit test. Then the unit test has no reflection itself.

Amy B
  • 108,202
  • 21
  • 135
  • 185
  • Well, as I've mentioned above, my coworkers used a method similar to what I intended to use for my unit tests when they performed a deep copy of one object to another. They had to scrap the code they've sunk 3 weeks of their time into because of the horrible performance, despite the code itself being very lean and graceful. – UkraineTrain Apr 26 '11 at 17:36
0

How fast do your unit tests have to run? Is a work around (avoiding reflection) a better use of your time to save some unit test time?

How long do your tests take right now? Until you implement your unit tests using reflection you will not know how fast (or slow) they really are, and will not be able to compare the alternatives.

Scott Bruns
  • 1,971
  • 12
  • 12
  • The reason why I want to use reflection is because I can write a whole lot less of unit testing code and thus save a lot of time. It's been estimated that as it currently stands, if implemented, unit tests using reflection would take up to 50 minutes to run, which is unacceptable. – UkraineTrain Apr 26 '11 at 16:53
0

One approach is to try to speed up reflection calls. Given that you are leaning on the low-level machinery to accomplish this, I don't see a lot of hope here.

Another approach is to pay the cost, but only pay it when testing is again necessary. (If you don't change the code being tested, you don't need to test it again).

Our C# Test Coverage tool can keep track of the relationship between (abstract tests) and the tested code. It can determine whether an (abstract) test needs to be run again by examining its coverage with respect to changed code, which it determines by comparing code files at the level of methods. If there's an intersection, you need to run the (abstract) test again. Otherwise you can simply skip those tests, and any expensive overhead ("reflection") they might contain.

The weasel words "abstract test" just means that you define what set of test activities corresponds to detectably retestable unit; you can decide to track every unit test, or group them in other convenient ways. Ideally you want the finest grain abstract tests you can get to minimize actual restesting; sometimes it is better to just lump a group of tests together.

Ira Baxter
  • 93,541
  • 22
  • 172
  • 341