3

Suppose I have a class with 3 fields/properties. Assume all my unit tests pass now in my project using this class. If I add a new property to this class(4th field) then I want one unit test to fail. How would I write such a unit test that can detect a property addition?

Blue Clouds
  • 7,295
  • 4
  • 71
  • 112
  • 3
    Im thinking reflection..but why would you want to do this? – anthonybell Sep 04 '14 at 14:48
  • @anthonybell I would guess it's for some sort of serialization, but yes, it's important to know the motivation. – Matthew Sep 04 '14 at 14:49
  • 1
    See http://stackoverflow.com/questions/737151/how-to-get-the-list-of-properties-of-a-class to get a list of all properties, then compare it with a saved list of property names and assert if there's a change? – dbc Sep 04 '14 at 14:53
  • @dbc that answers my question and to the question about motive. Unit test failing reminds us to write unit test for the newly added fields. There will be lot of lastminute changes that can override the normal test first development – Blue Clouds Sep 04 '14 at 14:58

3 Answers3

5

Here is an example using reflection.

void TheUnitTest()
{
    var p = new Person();
    Assert.That(p.GetType().GetProperties().Count() == 3);
}

public class Person { public String Name{ get; set; } public int age { get; set; } public String job { get; set; } }
anthonybell
  • 5,790
  • 7
  • 42
  • 60
  • 1
    You can use `typeof(Person)` instead of `new Person().GetType()`. – Lee Sep 04 '14 at 15:02
  • This is the best solution for my problem. Because I only need an indication that the field is changed. I do not need to keep track of all the field names. By seeing this failure I can take action to cover the newly added field in my unit tests. Many a times developers fail to add unit test to newly added field. – Blue Clouds Sep 04 '14 at 15:03
  • 2
    @BlueClouds Why are you testing fields? Fields are implementation, not functionality. You test behavior, not implementation. – Daniel Mann Sep 04 '14 at 15:08
2

You don't want to do that. The point of unit testing is to verify functionality, not implementation. You don't add a property on a class just to add it for fun -- you add it as part of implementing some new piece of functionality, and you test that functionality.

If you add a property and it makes no functional difference to your application, then that's fine. You don't need to test it, it's not changing anything about how your codebase functions. You'll test the properties via your tests of functionality.

Daniel Mann
  • 57,011
  • 13
  • 100
  • 120
  • agree with you. Here is a question, a developer adds a new field(with functionality) to a class and forgot to write a unit test to check it. How will you find it? Is it okay to ignore it? – Blue Clouds Sep 04 '14 at 15:11
  • 1
    The field will be tested via tests of the behavior that's built up around that field. Testing a "field" makes no sense. What is the test accomplishing? Testing a property *may* make sense if there's logic in the getter or setter, although the code in the get/set methods will still be exercised via your tests of the code that make use of that property. – Daniel Mann Sep 04 '14 at 15:16
  • I am sorry, I do not seem to get my point across, I rest my case. But as a last attempt: the tests you are talking about do not cover newly added field. because they were written before the new field was added. And the developer who added the new field(through a change request) only did the implementation code(no unit test). The developer just did not get time or forgot completely about unit tests. and days went on.. the newly added fields were never part of unit testing even though they carry an important functionlity – Blue Clouds Sep 04 '14 at 15:22
  • 2
    @BlueClouds in that case your review process or any other QA process is flawed. Solving these flaws in code is not the proper solution. – thumbmunkeys Sep 04 '14 at 15:24
  • @thumbmunkeys glad for understanding my situation correctly, could you please be more specific about improperness of this solution? We can only ask developers not to forget the unit tests. What else could we do? – Blue Clouds Sep 04 '14 at 15:27
  • @BlueClouds the scenario you described would be addressed by code & peer reviews. To add code to keep developers honest would be a nightmare on a large scale system. What about unit tests to verify comments? that could be a project requirement too.:) – Roman Mik Sep 04 '14 at 15:28
  • No 'comments' wont do the same damage as above, you know that (you can just say for the sake of saying:) ) . And this is the only problem that my unit tests cannot cover. rest all changes it can detect. – Blue Clouds Sep 04 '14 at 15:30
  • Developers not adding tests for new functionality is a process problem, not a test problem. You could enforce code reviews and (although I hate to say it) a metric like code coverage. Code coverage is a slippery slope, though. Personally, my code coverage threshold would be > 0%. If developers write bad tests to skirt the requirement, they should be fired. But that's *yet another* problem. :) – Daniel Mann Sep 04 '14 at 15:46
  • Yes agree. But to implement code review is not feasible in my project. Many a times as there wont be developers available or a quick deployment might be needed. Here is another guilty pleasure.. when you know a new field addition is going to be with out error(your experience says so) you can quickly implement it and deploy and later come back to write the unit test(provided TFS check is not implemented for unit test pass). So all these factors help me pin down on the solution mentioned above – Blue Clouds Sep 06 '14 at 05:22
0

I'm not exactly sure why you would want to do this, but here are some suggestions.

You can use the FluentAssertions library to do Assertions on types, methods, and properties. You could enumerate though the properties of the object and assert that each property's name is in a list of known properties.

If what you're trying to test is that you've got all your properties from a business object mapped to a DTO object (which is pretty much the only reason I can think to do this kind of thing), then consider using AutoMapper rather than rolling your own code- it has a method for testing that there are matching properties between two objects.

tom.dietrich
  • 8,219
  • 2
  • 39
  • 56
  • Thank you but that is not the reason. What do you think about the reason I have given (reply to @anthonybell) – Blue Clouds Sep 04 '14 at 15:07
  • I think that having a test for each property is not generally necessary, and what you likely want is some sort of test coverage check in your build process that alerts you when you've got less than the desired amount of coverage. (http://www.jetbrains.com/dotcover/features/) – tom.dietrich Sep 04 '14 at 15:30
  • Additionally, I agree with Daniel Mann's comments in his answer. I think you might be going down the wrong path in terms of what TDD is and adding additional cost for what will be a very low payoff. – tom.dietrich Sep 04 '14 at 15:31
  • this strategy of testing properties has worked for me and would like to continue. Ofcourse the solution we are talking about is some sort of a hack. But I would appreciate if you could be specific about the problem this approach costs. I understand from the response I get that this is not normal. but no specifics as to 'why'. – Blue Clouds Sep 04 '14 at 15:34
  • It would be very difficult to explain in only 600 characters. It sounds like you've been writing tests that set the value of a property and assert that the stored value is what you set, and these tests appear on the surface to be of dubious value unless you're writing a lot of property setters with business logic, which I'd generally advise avoiding in favor of methods to make it explicitly known to the users of your class that invoking this will have mutating effects on the class. – tom.dietrich Sep 04 '14 at 17:07
  • "It sounds like you've been writing tests that set the value of a property and assert that the stored value is what you set" Yes, I am setting value and checking if the stored value is correct . eg: I store values in DB and call a service method and check if the value retrieved by the service is same as what is stored in DB. Remaining part of what you said, I cannot understand unfortunately – Blue Clouds Sep 04 '14 at 17:28
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/60645/discussion-between-blue-clouds-and-tom-dietrich). – Blue Clouds Sep 04 '14 at 18:03