21

Here is an example of an class with no behaviour at all. So the question is should I be doing unit test coverage for it, as I see it as unnecessary for it does have any behaviour in it.

public class Employee
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public Address Address { get; set; }
}

My code coverage result complains that I have not done any coverage for the class

Cœur
  • 37,241
  • 25
  • 195
  • 267
HatSoft
  • 11,077
  • 3
  • 28
  • 43

8 Answers8

23

I never write tests for these. There's no behavior to test.

If there were any non-trivial behavioral code whatsoever (validation code, perhaps), then I would write a test for it.

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
  • 3
    I also think this represents a bug/bad setting in your code coverage tool. All of the coverage tools I've used (NCover, dotCover) exclude auto-properties from code coverage metrics. – nateirvin Oct 11 '12 at 19:57
12

I found this interesting article from Martin Fowler:

Test coverage is a useful tool for finding untested parts of a codebase. Test coverage is of little use as a numeric statement of how good your tests are.

===

Also this interesting quote from Object mentor:

It’s probably not mandatory and if your goal is 100% coverage, you’ll focus on that goal and not focus on writing the best tests for the behavior of your code.

Alfred
  • 60,935
  • 33
  • 147
  • 186
  • Cheers @Alfred brilliant article – HatSoft Oct 11 '12 at 18:55
  • 3
    +1 for the article, but it doesn't cover whether to write a test in this case or not. – jheddings Oct 11 '12 at 18:57
  • I don't think you should have to because change of defect in those parts are almost none existence... But then again if you don't feel confident you could also write tests for those parts. – Alfred Oct 11 '12 at 21:33
7

I could take it or leave it. But while there is little evident benefit now, you would be covered if a programmer later came along, converted those into traditional, member-field backed properties, and fumbled the implementation in the trivial case.

But I personally wouldn't actually bother, as my time is limited and I have more important tests to write which will provide bigger bang for my buck.

Anthony Pegram
  • 123,721
  • 27
  • 225
  • 246
7

Kent Beck in his "Test-Driven Development by Example" lists what you should test:

  • conditionals
  • loops
  • operations
  • polymorphism

Your class has none of these.

It often helps to ask yourself a question, "What do I gain if I cover this code with unit tests?". If "points towards some metrics" is the only answer you can come up with, it's probably not worth to write tests for such code. You'll spend time, produce extra code, and gain nothing (code-coverage "points" are of little value - at least in this context).

Also, have a look at those two questions (they both tackle similar issue, and answers primarily resolve around one important point - [in most cases] there's always somebody paying money for what you do - and that somebody might not be very thrilled knowing you spend your time improving ratings, as this is what it essentially is):

Final conclusion? I agree with others saying you should not test such classes.

Community
  • 1
  • 1
k.m
  • 30,794
  • 10
  • 62
  • 86
5

It is not a bad idea... Say, for instance, you develop a backend for storing this data in the future (e.g.to a database). You might replace the generic get; set; calls with additional custom functionality. Having the unit test ensures that your code is always exercised and that no errors are introduced in the transition.

Even a very simple test that checks to see you can create the object, set fields, and read back the same values shows that you are exercising the code with an expected behavior. Even if it is all obvious to you, future developers on that code will have the example to draw on and ensure any changes match your original design goals.

I also look at it this way: there is little to no harm in developing the test with some very possible long-term advantages. It only takes a few minutes now versus tracking down a problem introduced down the line.

jheddings
  • 26,717
  • 8
  • 52
  • 65
  • Even if you add new code, the original test (essentially a loop-back) could still pass (even if the new behavior is wrong), so I don't see how the original test is useful. – Robert Harvey Oct 11 '12 at 18:50
  • 2
    The only challenge with that is one could argue that it is not worth writing unit test for properties (if the code behind them doesn't matter). The point of a unit test is that you don't know what is happening behind the scenes. The test exists to ensure that the behavior contract remains the same under given conditions. Of course, adding new functionality to the class later should also result in more unit tests for the new "features." – jheddings Oct 11 '12 at 18:55
  • 1
    The practical problem of applying the approach to test "everything" is that from my experience it ends up in huge ammount of tests that no one cares about and sometimes even worse fewer and fewer team members update them if anything changes and even some tests break up - just because the code "is working" and there are so many tests that no one cares about.. I like TDD, but I also like the idea to review all the tests I wrote during my "programming session" and keep only the ones that somehow document what was done. – rudolf_franek Oct 11 '12 at 19:15
  • It is a fine line, for sure... Things that seem "obvious" and "trivial" today are often the things that bite us later. I certainly agree that all tests should be useful and simply writing a test doesn't ensure that is the case. The goal shouldn't be to achieve 100% test coverage, but to ensure that individual units of functionality are working as expected. Writing a test is necessary, but it is by no means sufficient. – jheddings Oct 11 '12 at 19:28
  • Replacing the auto-properties with functionality that connects to a database will really change the meaning of your class; for example, a simple getter-call could suddenly throw an exception. Unit-testing the surface structure, while ignoring the bigger picture, is not really helpful IMHO. – ruakh Oct 12 '12 at 00:07
  • @jheddings Way to test the compiler. Remember YAGNI - if you write tests for getters/setters you're wasting your time and your bosses resources. **Test for behaviour.** – Finglas Oct 13 '12 at 10:10
  • 1
    Even getters and setters have an implicit or explicit behavior, depending on the implementation. I work with a team of over 100 developers on mission critical software for both the government and private sector. Often times, tests are written against an interface, without knowledge of the implementation. In these cases, it is expected that a test is needed to verify the behavior of even a simple interface. YAGNI doesn't apply here. If you expect something to function a specific way, your expectations should be explicitly validated. – jheddings Oct 13 '12 at 17:40
  • 1
    Also note, I did not say that the test should be mandatory, only that it is not a bad idea to write tests now to avoid pitfalls later. The amount of time to write these tests pales in comparison to tracking an obscure bug down to a change in the way a property was get/set. – jheddings Oct 13 '12 at 17:47
  • 3
    @rudolf_franek I think that statement depends heavily on the intent of the codebase. If you're writing code that is completely rewritten every 6 months to a year, say a website. Then you're absolutely right. If, however, you are writing software that will remain mostly constant for years at a time, with incremental feature additions, these tests become regression tools to ensure each feature addition doesn't break existing functionality. – Myles Oct 13 '12 at 18:04
  • @jheddings your team and you are testing the C# compiler then. Getters/Setters are not behaviour. If they are used they'll be tested indirectly by other classes anyway. Every line of code has a cost, testing properties just adds more code to be built/tested/understood etc... – Finglas Oct 13 '12 at 18:15
  • 1
    I'm not sure why you would equate it to testing the compiler. I see it as laziness to avoid writing tests that validate expectations. The impact of a bug introduced in a project is 100-fold more costly than an automated unit test. To make it worse, approx 2/3 of the cost is passed on to your customer. A simple test to ensure that behavior doesn't change is a small price to pay. It is also dangerous to write tests knowing the implementation (i.e. auto-props vs. database access for properties). Making those assumptions can cause many hours of frustration. – jheddings Oct 13 '12 at 18:33
  • 1
    @Myles agreed... The point of the test is less about testing current behavior but creating a regression suite for large and ongoing codebases. – jheddings Oct 13 '12 at 18:35
  • @Finglas it's not "testing the compiler" because the properties do not necessarily have to work the way you expect. it's perfectly valid to have an empty setter, for example. it's also perfectly valid to accidentally return a different value from the getter. just because they are implemented as auto-properties right now does not mean they have to be. – Dave Cousineau Sep 03 '15 at 20:51
  • @Sahuagin, YAGNI. If you change the auto property to actually do something, then yes by all means add tests. But if they exist in the manner as the original question states then such tests are worthless. The callers will verify the auto property is "valid". Until then, lean on the compiler. – Finglas Sep 07 '15 at 17:22
  • @Finglas no, you're basically just saying "if you know the implementation is correct already, why write a test". the whole point of the test is so that you know right away if it changes. it being an auto-property or not is an implementation detail, something that should be irrelevant to the test. – Dave Cousineau Sep 07 '15 at 17:28
  • @Sahuagin this question is tagged TDD/BDD. In order to change from an auto property you would need to write a failing test first, then change the implementation. As an auto property there is no behaviour. If the auto property is not being used it can be deleted, otherwise some other part of your code will be calling get/set so it will be tested here. Test things that matter, logic, behaviour and get the best ROI you can. Feeling good about writing tests for things like properties is a wasted effort. – Finglas Sep 09 '15 at 06:58
  • @Finglas with TDD, in order to have written the class in the first place you would have had to write a failing test first. once the class and properties are under test, you don't need to write a failing test to change them, that's the whole point; they are under test so you can change their implementation with confidence. Also, the OP is wrong that an auto-property does not have behaviour, it's just simple behaviour. – Dave Cousineau Sep 10 '15 at 22:14
  • @Sahuagin the accepted answer and many others disagree with your definition of behavior then. I'll leave that with you now, write tests for this if it makes you happy. – Finglas Sep 14 '15 at 13:14
5

Alternative take on it: the fact that you don't have coverage on this particular class hints that there is some code that uses this class and that code does not have test coverage either. I'd solve that problem first and than see if more test needed.

As for testing such data-only object: I would definitely add explicit test if this object is part of external contract of library/unit. You promise that this data will be returned/consumed by your code. If there is no test verifying that you may change internals of the code and change this class you'll break the promise and nothing to stop you.

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
  • I assume that he mocked out the Employee class, bypassing code coverage for this particular class. – emory Oct 11 '12 at 20:58
  • @emory Why the hell he mocked class like this?! O_O It's just a Value Object, what's the reason for mocking it? He what, bound the custom listener to the attribute changes in it? – hijarian Feb 01 '14 at 16:19
3

If you just keep such classes as data transfer objects one could argue that you don't need unit tests for them. However, as soon as you start adding behaviour, then you should write the corresponding tests.

Looking at code coverage that could be returned as part of your built process may help as well to spot any missing tests.

As a short answer I would say "yes", for plain classes you can get away without getting their coverage.

Gorgsenegger
  • 7,356
  • 4
  • 51
  • 89
0

The point of unit testing is to keep your code "fixed" such that if you change the implementation, you do so knowing that you haven't broken anything, or that if you do break something you immediately know exactly what it is you broke.

A side benefit of this is knowing that your code as it is currently written does what you want it to do, but that is not (or not necessarily) the primary goal of unit testing. Unit testing is so that you can change your code with confidence.

If such a class as above is not unit tested, then the class can be broken without causing any test to fail. E.g.:

public class Employee
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get { return "Smith"; } set { FirstName = value; } }
    public Address Address { get; set; }
}

With unit tests you can know that something like this has not happened across your entire code base. (Is this specific example likely? maybe not. But something like this is very possible and basically innevitable.)

With just four simple unit tests, you can make this code "fixed", knowing that it cannot possibly change it's behaviour without a test failing*:

[TestMethod]
public void TestId() {
   var emp = new Employee { Id = 3 };
   Assert.AreEqual(3, emp.Id);
}

[TestMethod]
public void TestFirstName() {
   var emp = new Employee { FirstName = "asdf" };
   Assert.AreEqual("asdf", emp.FirstName);
}

[TestMethod]
public void TestLastName() {
   var emp = new Employee { LastName = "asdf" };
   Assert.AreEqual("asdf", emp.LastName);
}

[TestMethod]
public void TestAddress() {
   var address = new Address();
   var emp = new Employee { Address = address };
   Assert.AreEqual(address, emp.Address);
}

(*maybe except the side case of the broken implementation mimicking the values you use to test)

I won't implement it here, but you can also use reflection to make writing these kinds of tests easier. For example, you can build something relatively easily that would allow you to do the following:

[TestClass]
public sealed TestEmployee {
   [TestMethod]
   public void TestSimpleProperties() {
      Assert.IsTrue(
         SimplePropertyTester.Create(
            new SimplePropertyTestCollection<Employee> {
               { emp => emp.Id, 3 },
               { emp => emp.FirstName, "asdf" },
               { emp => emp.LastName, "1234" },
               { emp => emp.Address, new Address() }
            }
         ).Test()
      );
   }
}

You lose the benefit of having each property in its own test, but you gain the ability to modify the set of tests very easily.

You could also build a separate tester with a single test for each unit test, and then you keep the tests separate, but it's not a lot different than just writing them manually, and you end up writing basically the exact same line of code over and over and over.

One thing you can do is put Console.WriteLine statements in the Test() method, and then you should be able to have some textual output to look at to pinpoint the problem a lot faster.

EDIT: Actually I've now gotten these to look like the following:

[TestClass]
public sealed TestEmployee {
   [TestMethod]
   public void TestSimpleProperties() {
      var factory = SimplePropertyTestFactory.Create<Employee>();
      new SimplePropertyTestCollection<Employee> {
         factory.IntTest(emp => emp.ID),
         factory.StringTest(emp => emp.FirstName),
         factory.StringTest(emp => emp.LastName),
         factory.ReferenceTest(emp => emp.Address)
      }.Test();
   }
}
Dave Cousineau
  • 12,154
  • 8
  • 64
  • 80