Agile Practices


.Net Development&Automated Testing10 Jun 2011 10:10 pm

I just found this gem in a post on another subject on Krzysztof Koźmic’s blog and thought it merited its own post. Beautifully simply solution for asserting that a class doesn’t hold a reference to an object that it should not.

[Fact]
public void Freezable_should_not_hold_any_reference_to_created_objects()
{
    var pet = Freezable.MakeFreezable<Pet>();
    var petWeakReference = new WeakReference(pet, false);
    pet = null;
    GC.Collect();
    Assert.False(petWeakReference.IsAlive, "Object should have been collected");
}
Agile Practices08 Jan 2010 04:19 pm

My current project is the first that I have been involved in where we are really doing TDD in a meaningful way, but, with no veteran agilest on the team, we are feeling our way along as we go. Coming to the end of our first full sprint, things seem to be doing pretty well. Yet they don’t seem to be going like any TDD I have read about. So, I thought I would blog about what we are doing and see what feedback I get.

To set the stage, this is an asp.Net MVC 2.0 application written in C#. The website sits in a DMZ and the application and data layers are hosted on another set of machines behind a firewall.

In our effort to do true TDD, we start with a user story. From this we write one or more BDD stories using NBehave that execute against a controller in the web application. These tests are not unit tests of the controller however but integration tests. We are only mocking two sets of classes: 1) We are using the types in the System.Web.Abstractions assembly (or our own abstractions where necessary) to decouple our tests from ASP.net and the .Net framework. 2) As we go we define the methods needed on the interface to the application layer and mock the application layer via that interface. Thus our BDD stories test the whole of our web application code (excluding views) as an integrated whole.

Once we have these tests passing, we do a similar thing with our application layer. 1) We write BDD tests to against the interfaces defined in the previous exercise. 2) We write implementations that make the tests pass and in the process define and mock the interfaces needed for the data access layer and peripheral services.

Penultimately, we implement the peripheral services and write integration tests against their interface where practical.

Lastly, we go back to the web layer and implement the views. (Above we only stub out these views to the degree needed to all us to write our controller tests). We wait until the end to do the views because the views have to be human tested anyway and this allows us to basically do end-to-end systems tests while testing out the view under development.

We do this iteratively in tight vertical slices of functionality, and refactor in between iterations. In the end we have a nice little workflow that starts at testing the controller interface and ends with a reasonably rigorous albeit manual systems tests.

On the whole, this seems to be pretty solid TDD. Our automated tests are BDD tests that map directly to needed application behavior. We only write code to satisfy the tests and we can refactor at will inside the respective layers w/o having to modify the tests but knowing we have full functional coverage.

But note the lack of low level unit test. It is not the case that we don’t have any. We have a fair number, but they are not driving our TDD effort. The higher level BDD tests are doing that.
We write unit tests when we have a complicated piece of code that we want to test in isolation to make sure it handles all the edge cases. (We are using NUnit’s new data driven test cases for this sort of thing.) But we also write data driven NBehave tests as well at the integration layer so that we know the application as a whole handles a representative set of those edge cases.

The problem we have encountered with the lower level tests is their fragility. When we refactor, classes get broken up, or combined and the tests against them break and have to be retooled. The higher level abstractions and interfaces are more stable and therefore the integration tests against them remain valid in the face of the lower level refactorings.

The only concern I really have going forward with our approach is the possibility of the tests taking too long to run at some point. Right now we have about 260 test that run in just under 20 seconds. Given that some of these test are data driven tests that actually run hundreds of times the total count of test executions is actually over 1K. Considering this, if we do run into speed issues, the first line of attack may be to curtail some of the more extreme cases of data driven unit testing. Next on the block would be to omit the database integration tests which account for about one quarter of total execution time at this point.

In the end, thought, this is working for now but I would like to hear your thoughts on this and hear how you do it. Happy Coding!

Agile Practices29 Nov 2009 09:50 pm

For any of you who know who Uncle Bob is, you probably know he is a “fanatic” about the idea that methods should do one and only one thing.  If you have any doubts about this, check out his recent blog on the matter.  However I put “fanatic” in quotes because I am in complete agreement with him on this (and most other) points.

There are lots of reasons for keeping your functions this tight.  Combined with good method names, it makes for great self-documenting code.  It makes code reuse a lot easier because you never have code that does one thing tangled up with code that does something else.  That in turn makes it easier to keep your code DRY; if code is easily reused, there is rarely any reason to duplicate it.  All of these points, and their relationships, are often discussed.

One relationship I have not seen mention of, though it is implied in the above, is the relationship between Do-One-Thing (DOT) and the Open Closed Principle (OCP).  This relationship has had opportunity recently to re-impress itself upon my mind, so I thought I would take some time to discuss it.

For those not familiar with OCP, the Wikipedia entry gives a concise explanation.  For a more in depth, applied look, see Uncle Bob’s treatment of it.  For the real short summary, here is the definition from the latter.

Software entities (classes, modules, functions, etc.) should be open for extension but closed for modification.

Another way to say this which gives the sense in which I wish to discuss it here is this: Given an existing class, if I need to modify the behavior of the class, I should be able to do so solely by means of subclassing it.  I should not need to make any modifications to the class itself.

To clarify, this is important in scenarios where the original class is used by code beyond that which needs the modification.   If all code that uses a class needs the modification (such might be the case with a bug fix) then by all means the original class should be modified.  But if a modification is needed by only some users of the class, then OCP comes into play.  In this case we want to leave the original class unmodified in order to ensure that the other users are not affected by the change.  The code which needs the change, and only that code, uses the new subclass.

In contrasts to OCP, what often happens is this:  I have a new feature to implement that requires a slightly different behavior from the FooBar class.  FooBar is used by other features of the application that rely on the current behavior.  I could just make a copy of FooBar and modify it to fit my needs, but DRY says that is bad, so I correctly decide to subclass FooBar and just override the method that needs to behave differently.  So far so good.

So I pull up the source code for the FooBar class and find the code that I need to override.  It is in the Transmorgify() method.  But now things get messy.  Transmorgify() doesn’t adhere to the Do-One-Thing principle.  It does several things.  But I only need to override one of them.  Now I am in a conundrum.  I have two options.

  1. I can override the current Transmorgify() method and copy its current implementation into my override, and modify the part that I need modified.  That violates DRY.
  2. I can refactor Transmorgify() by extracting each behavior into its own function as Uncle Bob demonstrated above–then override the new more narrowly focused method. But that means modifying the existing code and possibly breaking something–a potentially costly error.

As can be seen, the failure to adhere to Do-One-Thing resulted in a failure to adhere to the Open Closed Principle.  To put it succinctly, a class cannot be closed to modification if any behavior that might, in the future, need to vary independently of another behavior is implemented in the same method as that behavior.

That is an ideal statement.  Realistically, it may be hard to identify every potential vector for change let alone isolate them.  And even if it can be done, the ROI might not be there.  Uncle Bob himself acknowledges this in his treatment of OCP.  (See page 6 on “Strategic Closure.”)  But this really goes back to the question of how far to take Do-One-Thing.  If you can, “do it till you drop.”  But if time constraints and ROI issues impose, then at least go as far as you can and error on the side of excess.  Why? Because we are human and we tend to error the other way because it is easier and faster.  So trying to error on the side of excess is more likely to get us into an appropriate middle ground.

No matter how hard we try to avoid them, ultimately, we are going to encounter scenarios like the above.  When it happens, the best thing is to have a comprehensive set of tests in place and refactor the original class as needed.