Advantage of DDD approach to problem

If you read my last post, I explain how I solved a really stupid problem of managing a Traffic Light using OOP principles and the concept of Domain Events, now I want to emphasize some of the advantages you have using this approach.

One benefit is in unit testing, suppose you want to test that a traffic light in red state does not cancel the request of another Traffic Light that want to become green.

[Fact]

public void verify_that_a_red_traffic_light_permits_other_to_become_green()

{

    TrafficLight.TrafficLight sut = TrafficLightFactory

        .WithStatus(LightColor.Red.State())

        .Create();

    MayITurnGreen msg = new MayITurnGreen();

    sut.MayITurnGreen(msg);

    _domainEvent.Should().Be.Null();

    msg.Cancelled.Should().Be.False();

}

This test is really simple, thanks to a simple factory, I’m able to create a traffic light in red state, then create a MayITurnGreen message and pass to the MayITurnGreen() method of TrafficLight. The test is really simple, but I want to emphasize the assertions.

I’m inheriting this test class from a base test class that register itself for Domain Events and the last event is always stored in the _domainEvent field of the test class. This permits to assert not only that msg.Cancelled is false (when a Traffic Light is in red status it should not prevent other Traffic Light to become green), but I’m able to assert also that no Domain Event were raised during this request.

This kind of testing is really important, because since Domain Events capture important events occurred in the past, being able to assert on them means that you are able to assert on every important event that happened to the domain during the test (this is really powerful). Let’s see another test

[Fact]

public void verify_that_a_green_traffic_light_after_ten_seconds_prohibit_to_become_green_but_becomes_yellow()

{

    TrafficLight.TrafficLight sut = TrafficLightFactory

        .WithStatus(LightColor.Green.State())

        .Create();

    MayITurnGreen msg = new MayITurnGreen();

    AddSecondsToTestTime(15);

     sut.MayITurnGreen(msg);

    _domainEvent.NewStatus.Should().Be.EqualTo(LightColor.YellowFixed);

    msg.Cancelled.Should().Be.True();

}

As you can see this test verify that, when 15 seconds are passed (this test is based on green time of 10 seconds) and someone ask to a Traffic Light in Green Status if it can become Green, it answers NO(cancelled == true), but also it become YellowFixed because 10 seconds are passed and it can become red to permit other Traffic Light to become green after yellow time will pass.

As you can see, the OOP and DDD approach can even simplify your tests.

Gian Maria.

Unit testing floating point numbers

Testing for equality Floating point numbers is usually a bad idea, this because rounding occurs with floating point operations and you need to test with a tolerance. Suppose you test that some algorithm produces the expected result and you find that unit test fails with this message.

SharpTestsEx.AssertException : 2.36 Should Be Equal To 2.36.

This seems strange, but the problem is that the real value is 2.360000000003 that surely is different from 2.36. Now you have two different scenario, the first one is the test is wrong because I want to verify that the two numbers are really equals. With floating point calculation this cannot be achieved, you can use numbers with high precision, but doing operations with any floating point numbers lead to rounding, and you should never test for equality two floating point numbers.

A second and better scenario is when you the test is expressed with a tolerance, so you can write this assertion.

   1: result.Should().Be.EqualTo(expectedresult, 0.00001)

This is a better assertion, I’m asking if the result is different from the expected value with a 0.00001 tolerance. This is possible with a simple extension of SharpTestEx.

   1: public static IComparableBeConstraints<Double> EqualTo(

   2:    this IComparableBeConstraints<Double> constraint,

   3:      Double expected, 

   4:      Double tolerance)

   5:  {

   6:      constraint.AssertionInfo.AssertUsing<Double>(

   7:          new Assertion<Double, IComparable>(

   8:              "Equal to", expected, a => Math.Abs(a - expected) <= tolerance));

   9:      return constraint;

  10:  }

Such test is much more interesting and correct, because it states the tolerance that you can suffer before stating that the algorithm is wrong.

Alk.

Test infrastructure

Unit tests must be as clearer as possible, I found that in standard project I’m working, I use nhibernate + stored procedures for massive operations. Most of the tests contains code to preload database, recreate structure or manage transaction, so, lot of time ago I decided to build some infrastructure to make this possible.

image

It makes my test really simple to read. This test use SqlServer, and it needs to be transactional, so every test run inside a Transaction, but I can specify more complex stuff

image 

I can ask to clear the database at each test, I can ask also to execute all the tests with integrity check disabled, and also I’m able to make the test impersonate specific user, belonging to specific role.

I know that spending some time, building an infrastructure for your test can give you great value.

Alk.

Tags: