views:

299

answers:

2

I have a class (of many) that have properties. Some have logic in them and some don't. Assuming I want to test these properties, how do I go about doing that?

Recently, I've been interested in BDD style for creating unit tests.

see here and here.

So I'd do a setup of the context - basically create the SUT and load up whatever is needed. Then in each Observation (test method), I'd verify that a particular property contains what it should contain.

Here's my question. If the SUT has 20 properties, then do I create 20 Observations/Tests? Could be more if one of the properties contained more interesting logic I guess.

[Observation]
public void should_load_FirstName()
{
    Assert.Equals<string>("John", SUT.FirstName);
}

[Observation]
public void should_load_LastName()
{
    Assert.Equals<string>("Doe", SUT.LastName);
}

[Observation]
public void should_load_FullName()
{
    Assert.Equals<string>("John Doe", SUT.FullName);
}

But would it be better if aggregated the simple ones in a single observation?

[Observation]
public void should_load_properties()
{
    Assert.Equals<string>("John", SUT.FirstName);
    Assert.Equals<string>("Doe", SUT.LastName);
    Assert.Equals<string>("John Doe", SUT.FullName);
}

Or what if I used a custom attribute (that can be applied multiple times to a method). So that I can possible do, something like:

[Observation(PropertyName="FirstName", PropertyValue="John")]
[Observation(PropertyName="LastName", PropertyValue="Doe")]
[Observation(PropertyName="FullName", PropertyValue="John Doe")]
public void should_load_properties()
{
}
+4  A: 

In general you should strive after having only one logical assertion per test. The excellent book xUnit Test Patterns contains a good discussion about that, but the salient point is that it makes it easier to understand where a violation occurs if there's only one reason a test can fail. That's probably a bit more relevant for Regression Testing than BDD, though...

All this implies that your option of writing a single test that verifies all properties is probably the least attractive, although you could argue that verifying all properties is a single logical assertion...

A more central tenet of xDD (TDD, BDD, whatever) is that tests should act as Executable Specifications. In other words, it should be immediately apparent when you look at the test not only what is being tested, but also why the expected value is as it is. In your examples, it is not very clear why SUT.FirstName is expected to be "John" and not, say, "Jane".

If at all possible, I would write these tests to use Derived Values instead of hard-coded values.

For writable properties, I often write tests that simply verify that the getter returns the value assigned to the setter.

Fore read-only properties, I often write tests that verify that the value matches a constructor argument.

Such tests can be encapsulated into reusable test code that encapsulates common testing idioms. I'm currently working on a library that can do just that.

Mark Seemann
Thank Mark for the advice. Way back when, your blog posts on CallContext helped me out a lot!I followed the link to Derived Values on Meszaros's site and read about it (after yours). I am not sure I'd go to the extreme of implementing it as you did for your Reverse example. I think having a variable, expectedResult right next to the input and then just use the literal value.In my case above, I hear you - it's not apparent but I am loading test data from local disk to create the SUT (it's an acceptance/interaction test). I need to find a better way to specify the input values...
Jiho Han
A: 

Have a look at the other SubSpec syntax (the [Specification] example) - in that case, each one of Asserts at the end represents a separate execution of the test. I originally discounted the syntax as lambda abuse but like it now I've been using it for a while.

Ruben Bartelink