Code Elegance

1024 Tests

I love Unit Tests, and I feel very confortable when the number of tests is high :-)

1024

No comments

Random thoughts on TDD

Here it is a flow of random thoughts about Test Driven Development. Naturally IMHO.

  • TDD is not about testing application is about design application, and have a (nice) side effect that creates a suite of tests
  • The Test obtained with TDD does not cover all the cases, but you can write more test when you need new cases or find a new bug
  • The code written in TDD is less and it focused on the needs
  • The code written in TDD is more orthogonal and simpler to maintain
  • The first red bar is the signal that the test is testing something (and it is very important)
  • The tests cannot contains if, switch, etc…so they need to be simple
  • Learning TDD is difficult: the impact is the same that you have when passing from structured programming to Object Oriented Programming
  • Learning TDD requires times and perseverance
  • You cannot learn TDD reading articles and books, you must try it
  • Every piece of code is testable
  • Testing that the tone of red is that the user likes is not a task of TDD
  • With the right use of Mock Objects you can test that the gradient is correctly set
  • The test cases comes from the User Stories written with the customer and then they responds to requirements
  • The Team that use TDD must be skilled enough…and Pair Programming helps a lot
  • The Test code is bigger than the tested code
  • TDD force you to think about what you’re writing
  • TDD force you to declare what you need before writing something
  • TDD put the developer to the client side of his code and so help him to write better interfaces
  • TDD helps you to write cleaner and decoupled code
  • The Integration Tests helps you to understand how your class interacts with others
  • When you need to refactoring your code you can start from tests
  • Tests are documentation: read a test is a great help to understand how to use your class
  • TDD does not guarantee that you code doesn’t contains bugs
  • TDD guarantee that old bug doesn’t come to life again
  • The start up cost of TDD is write off during the life of the project
  • The TDD reduce a lot the time needed for manual testing
  • With TDD the debugger is used like a surgery tool
  • TDD helps you to simplify the problem dividing it in small part and every solved part is a small step to the final solution
  • Every test case is a single functionality: if one test fail you have only one problem
  • If  you have two red test you have two distinct problems
  • Every test add a new functionality to the code
  • Is difficult to test multi threading applications
  • It’s expensive testing the UI, but there are patterns that decrease the UI code (MVP/MVC)
  • The integrations test against database help you to know if the database and the queries are ok
  • TDD force you to written less encapsulated code to  make it testable
  • TDD force you to write independent object and to inject all the dependencies
  • Write test after code is not always possible
  • TDD is not a silver bullet (but it’s help a lot!)
No comments

TDD as a metodology

TDD is often considered a practice for writing test. It isn’t: TDD is a design practice.

Time ago, while developing an application, it happens that I need to write a resource schedule algorithm. I’m not an expert in schedule algorithms, I read some paper, I know that exists various methods more or less complicated, but the one that I need was quite simple and so I preferred to write it by myself using small steps and TDD that helps me a lot.

I collected the specification from customer, wrote some stories and ordered the stories by complexity, then I begin to write the first test.

The first test try to schedule a single resource always free on a unlimited and free time lap. When this was green I wrote another one with 2 resources, then 3, then N.
Then I wrote other tests that reduced the available time, others that introduce overlapping schedules, to arrive to a test that reproduce real world cases with N resources on N projects with small time available.

What I did is to add a little complexity on every new test and having all the previous green test help me to stay on track and to keep the algorithm right. On every green test I did some refactoring to keep the design clean.

After 2 dozens tests I had the full algorithm ready to use with a suite of test that proved it. I don’t know if this is the best algorithm, I know that it is not the fastest one but I know that it satisfy the customer requirements.

Naturally after the deployment the customer begin to use it and she asked for some modification. If in general this kind on modification on this complicated algorithm is very difficult and dangerous to implement, if you have a suite of test that in a bunch of seconds verify that everything is going right you can write the new requirements quite relaxed adding new tests.

Here the TDD has a double value: first it helped me to resolve a complex problem step-by-step keeping always under control the status of the project, second it helped the introduction of new requirements requested by the customers.

2 comments

On writing good tests

When you start with Unit Testing it’s difficult to write good test. My first test were very ugly, a lot of code to setup the mock objects and a lot of asserts in the same test. Test written in this way are difficult to maintain and every little change that break the test leave in the developer a bad feeling and a diffidence in the Test Practice. He need a lot of time to find  out what’s break and why it is red.

Take a look at the following example:

[Test] public voidConstructor_ShouldDoSomeThingOnViewAndModel()
{ IDtoMapper mapper =MockRepository.CreateMock<IDtoMapper>(); IMyView view =MockRepository.CreateMock<IMyView>(); IMyModel model =MockRepository.CreateMock<IMyModel>(); IList<DomainModelData>dummyData = new List<DomainModelData>(); IList<DtoData>dummyDto = new List<DtoData>(); view.Expect(v => v.Save += null).IgnoreArguments(); model.Expect(m =>m.GetData()).Return(dummyData); mapper.Expect(m =>m.ToDto(dummyData)).Return(dummyDto); view.Expect(v =>v.SetDataContext(dummyDto);
  new MyPresenter(view, model, mapper);
  view.VerifyAllExpectation();
  model.VerifyAllExpectation();
  mapper.VerifyAllExpectation();
} 

It smell, isn’t it? What are the problems?

This test is testing too things, then is not readable and it depends on too many objects. That means that if in the next weeks I need to change it, it take too much to understand what it does and if it become red I can figure out why.

The direction in which I’m going is in where I have a lot of simple test in which every test use only one mock object and verify only one functionality.

So that test become four tests:

1) One that verify that the presenter is correctly subscribed to Save event from the view
2) One that verify that the presenter use the model to get the data to visualize
3) One that verify that the presenter calls the method ToDto on the mapper to convert the Domain Model Object in a Data Transfer Object to pass at the user interface
4) One that verify that the presener pass to the view the DTO with data to visualize

It seems hard? Not really:

- The new tests are more readable
- The new tests documents much better the functionality
- If a test fails I know exactly what doesn’t work
- Write 4 tests instead fo the one like the above one is not so hard ;-)

The result can be like this:

[Test] public void Constructor_ShouldSubscribeToViewEvents() { IDtoMapper mapper = MockRepository.CreateStub<IDtoMapper>(); IMyView view = MockRepository.CreateMock<IMyView>(); IMyModel model = MockRepository.CreateStub<IMyModel>(); view.Expect(v => v.Save += null).IgnoreArguments(); MyPresenter presenter = new MyPresenter(view, model, mapper); view.VerifyAllExpectation(); } [Test] public void Constructor_ShouldGetDataFromModel() { IDtoMapper mapper = MockRepository.CreateStub<IDtoMapper>(); IMyView view = MockRepository.CreateStub<IMyView>(); IMyModel model = MockRepository.CreateMock<IMyModel>(); IList<DomainModelData> dummyData = new List<DomainModelData>(); model.Expect(m => m.GetData()).Return(dummyData); MyPresenter presenter = new MyPresenter(view, model, mapper); model.VerifyAllExpectation(); } [Test] public void Constructor_ShouldGetDtoUsingMapper() { IDtoMapper mapper = MockRepository.CreateMock<IDtoMapper>(); IMyView view = MockRepository.CreateStub<IMyView>(); IMyModel model = MockRepository.CreateStub<IMyModel>(); IList<DomainModelData> dummyData = new List<DomainModelData>(); IList<DtoData> dummyDto = new List<DtoData>(); mapper.Expect(m => m.ToDto(dummyData)).Return(dummyDto); MyPresenter presenter = new MyPresenter(view, model, mapper); mapper.VerifyAllExpectation(); } [Test] public void Constructor_ShouldSetDataContextOnView() { IDtoMapper mapper = MockRepository.CreateStub<IDtoMapper>(); IMyView view = MockRepository.CreateMock<IMyView>(); IMyModel model = MockRepository.CreateStub<IMyModel>(); IList<DtoData> dummyDto = new List<DtoData>(); view.Expect(v => v.SetDataContext(dummyDto); MyPresenter presenter = new MyPresenter(view, model, mapper); view.VerifyAllExpectation(); }
No comments