Tuesday, 19 February 2008

Dynamic app.config settings for testing

If you need to write tests that verify behaviour based on different app.config settings, here’s a neat way of doing so.

In your [SetUp] method, load the app.config into two separate instances of the Configuration class, like so:

[SetUp]
public void SetUp()
{
//load config so it can be edited for tests
_originalConfig = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

_currentConfig = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
//any other init code here
}


In your [TearDown] method, ensure that you restore the app.config to the original (presumably you want it to be the same every time your tests start).

[TearDown]
public void TearDown()
{
_currentConfig = _originalConfig;
_currentConfig.Save();
}


When you need to modify any part of the config you can do so (provided there’s a “set” property for the element or attribute) at runtime like so:


[Test]
public void MyTest()
{
//... set up stuff here ...

//modify config for this test. Set the lockout period to 120 minutes
//_client is an instance of a custom configuration element
int lockoutPeriod = 120;
_client.Profiles.PasswordLockoutPeriod = lockoutPeriod;
_currentConfig.Save();
ConfigurationManager.RefreshSection("clientSettings");

//... carry out your tests here ...
}


Pay particular attention to the call to ConfigurationManager.RefreshSection("clientSettings");. The change I made to the config is within this section and so I want to refresh it before continuing in order to ensure that the new version is used.

Also note that any objects that reference the config need to be re-loaded after you’ve modified (and refreshed) the config in order to get the changes. For example, if you have loaded an instance of a class in your SetUp that uses config you'll have to re-initialise that class after making your config changes in a test.

Sunday, 17 February 2008

Dependency Injection is an easily confusing topic

It took me quite a lot of time to get my head around the Dependency Injection pattern. Getting a simple answer to the question "what is Dependency Injection" is not easy. And when you think you "get it", you'll come across an article or a statement that confuses the issue.

So I was happy when I found this citation on Andrew Binstock's blog:

"Any nontrivial application is made up of two or more classes that collaborate with each other to perform some business logic. Traditionally, each object is responsible for obtaining its own references to the objects it collaborates with (its dependencies). When applying DI, the objects are given their dependencies at creation time by some external entity that coordinates each object in the system. In other words, dependencies are injected into objects."

I don't think you can put it simpler than that. I'll be writing more about Dependency Injection as part of my series on TDD so I'll return and try and show with some examples how to use Dependency Injection and give some good reasons why you may want to use it.

The confusion around this topic stems, I think, from the fact that Dependency Injection is almost always discussed in the context of a Dependency Injection framework such as PicoContainer or Spring. These frameworks are no doubt very useful, but I don't think bringing them into the mix when explaining the pattern adds value to the discussion.

The definitive article on Dependency Injection was written by Martin Fowler and I recommend reading it despite it's use of various frameworks in its examples.

Test Driven Development, part 2. Why TDD?

In my first post on Test Driven Development I introduced TDD as a development methodology and showed, without going into a deep level of detail, how TDD encapsulates high level software requirements and break these into low-level unit tests which are defined and written before any actual production software is written.

Why use the TDD Methodology?

In this post I want to explain why TDD is a good way of writing software and what benefits the methodology yields to software projects where requirements are changing continuously. If you are not familiar with TDD it may be a good idea to go back and read the first part of this series.

It is a statement of obvious fact that testing is necessary for any type of software development effort. Testing can be carried out in a variety of ways, so why is TDD better than the other approaches? The simple answer is that since TDD makes you think of your tests first, all your software development is focused on passing these tests. And as each test is a representation of a software requirement, the entire software development process drives towards meeting the pre-defined, clear requirements specified up front. Instead of a traditional approach where testing happens after development in a kind of "let's test to see if we got it right" mentality, TDD changes the testing mentality into "now that we have our tests, we had better get this right."

A further benefit of the up-front testing approach of TDD is that every unit of code that is written already has a test. This means that as the software grows, so does the number of tests, and there is no need to go through an exercise to create tests once the development phase is over. The tests are defined and written when necessary as new parts of the software are developed or as requirements are added or changed.

Additionally the tests that are written during a TDD project can be run any time to verify the integrity of the produced code. This is an absolutely invaluable aspect of TDD. The fact that you have a click-and-run verification process at your fingertips means that changes to software (requirements changes or refactoring) can happen quickly and safely. If you change a single line of code, re-write a method or an entire class, a single run of your tests will verify whether your code still functions like it should. The bigger the software project, and the more developers changing and adding code on the project the more valuable this aspect of TDD becomes. Just imagine an application with 25 libraries and ten developers working for three months to complete the project. Every single day each developer will commit (on average) changes at least once. Over the course of the three month period that means there are rougly 600 opportunities for introducing bugs into the central code base. With TDD and automated testing any bug introduced into the code base will be flagged at the first test run and can be fixed when it is introduced rather than weeks hence when nobody can figure out where it came from.

More subtle benefits of TDD include those that emerge from the step-by-step process of test and code creation. This will be covered in much greater details in a later post on how TDD is practiced, however it can be said here that the relatively strict guidelines of the TDD methodology encourages brevity, clear and logical encapsulation, and discourages bloated methods. TDD methodology forces you to write testable code, and following the guidelines will yield better, more readable, and more economic code. A common problem with non-TDD approaches is that code ends up being very hard to test (in an automated manner) because of the way the code is written. With TDD this problem is not prevalent.

There are some developers that subscribe to unit testing and automated test runs, but who do not believe in the TDD methodology. The most common reason I am met with goes something like "How can you test your tests? If you cannot test your tests you cannot be sure that your tests are correct. If a test is incorrect the resulting software will have incorrect behaviour. As such, TDD is an unsafe approach." I sometimes am told that TDD requires a very mature team of developers in order to function, and there is also a lot of doubt as to whether the up-front effort required to write tests pays off in the long run. "It's so time consuming," they say.

These are all valid concerns, but they typically stem from a lack of understanding of the underlying TDD methodology. It is true that you can end up writing tests that are incorrect. I have certainly done that more than once. However I know that I have written incorrect tests because eventually these incorrect tests have been caught out by other tests that I have created later. Writing an incorrect test amounts to roughly the same level of severity as misunderstanding or omitting a an untested software requirement. The fallout is determined by how badly wrong the test was written. The risk of these things happening is not minimised by creating layer upon layer of tests for your tests, but rather through clear communication and channels for requirements elicitation and documentation both prior to development and during the development phase.

I do not believe that TDD requires a "very mature team of developers". Rather I believe it requires a team of developers with clear vision and great aptitude. A developer's number of years of experience "in the field" does not determine whether or not he is fit for TDD. It is true that the TDD methodology requires practise and is not learned quickly, but this does not mean that it cannot be taught to or practiced by juniors. On the contrary, TDD teaches very good software development skills and can be an excellent tool in the education of inexperienced developers.

But of course, TDD in the hands of sloppy developers will not yield better software than that team would using any other methodology. TDD is not a silver bullet. Nothing is. If you believe it is you'll end up shooting yourself in the foot.

My answer to the argument about TDD being time consuming usually centers around examples from my own experience. Recently I had to add a single member field on a class, load the value for that field from a database, and ensure that the field was transferred properly from the data access layer to a WCF service layer. It took me between four and five hours to write all the tests and code required. I'll add that the data access layer involves custom data mapping with iBATIS and is a little bit more involved than what you would normally assume, but four-to-five hours for this task probably sounds like a lot of effort for what I accomplished. But the pay-off for all that work came shortly afterwards when a change elsewhere in the system caused my newly written tests to fail. And they failed for reasons I had not even thought of - so chances are that without the tests in place this bug will have gone unnoticed for much longer. It's difficult to quantify how much effort would have gone into discovering, hunting down and fixing the bug, but I am pretty sure that it would have taken me at least an hour - maybe two. So if two and a half of the total five were spent writing my tests I've already had a significant return on my investment. And the best thing of all is that this investment will keep yielding a return, because the tests are still there and still running.

Finally, some people are simply more comfortable writing unit tests after development because this approach is more familiar and in line with the write-first-test-second approach that we all know so well. To this I submit that "test-after is better than no test at all", but also offer two points of reflection on why TDD is still the better alternative:

When you write unit tests after writing code you run into a dilemma once a test you’ve just written fails.

  1. If your test fails because you wrote the wrong test for your unit you will have to change your test to suit your code. This is inherently dangerous because at this point you’ve no assurance that your unit actually does what it should. A test that has been retrofitted in this manner can end up showing false proof that a unit behaves correctly when it does not
  2. If your test fails but is the correct test for your unit you have to change your unit so that it passes the test. This is exactly what’s at the centre of TDD methodology. Your tests should come first to provide the benchmark for your units. In this scenario you end up applying TDD principles, and it is better to adhere closely to these and apply them up front.

In my next post I will be writing about the how of TDD, going into practical code examples and discussing the step-by-step methodology that yields this amazing result I have spoken about here today.

Monday, 11 February 2008

WCF Data Contract translation

In WCF you often pass data between the client and service in serializable classes marked up as Data Contracts. These classes are supposed to be data containers only and should not contain business logic. Whenever a class of this type is received on the service side is therefore translated into a business object of some sort before processing takes place.

A straight-forward way of doing this translation is to set up a little translator class with a method that takes a parameter of type X and returns an object of type Y, and to manually code the translation between the two in the method body. The drawback here is that you have to explicitly code the translation both from X to Y and from Y to X. I thought I had a better solution.

Because of an earlier, lengthy refactoring exercise a couple of Data Contracts (that were also business objects) were now split into two classes - one a Data Contract for the service, and one a Data Transfer Object for the data access and mapping layer. These two classes shared a number of properties and because of this their common interface was abstracted out. And this led to really easy translation, because the translator could simply translate treat two types implementing the same interface as the same type.

public static IProfile Translate(IProfile input)

This method allows the caller to control the types going in and coming out, through type casting.

//the object "input" is of type DataContracts.Profile
DataAccess.Profile = (DataAccess.Profile) Translator.Translate(input);


This works just fine for simple object-to-object translation (e.g. DataAccess.Address to DataContract.Address), but with nested objects I ran into trouble. For example, IProfile declares a public property of type List. With the above approach we run into trouble because there's no way of telling the Translate(IProfile) method what type the contained list of IAddress is.

So it became necessary to be a bit more type specific. The Translate() methods were rewritten with generics like so:


public static T Translate(IProfile input) where T : IProfile, new() {}
public static T Translate(IAddress input) where T : IAddress, new() {}
//... and so on


And now, by adding an extra property public Type AddressType {get; set;} on IProfile we could make use of the MethodInfo.MakeGenericMethod(Type) to call the correct method on Translator to translate the right type of Address for the IProfile object, like so:


// ... this is all in class Translator

public static T Translate(IAddress input) where T : IAddress, new()
{
//... translation logic for addresses goes here ...
}

public static T Translate(IProfile input) where T : IProfile, new()
{
T output = new T();

// ... do the member-specific translation here ...

if (input.AddressList.Count > 0)
{
foreach (IAddress inputAddress in input.AddressList)
{
MethodInfo method = typeof (Translator).GetMethod("Translate", new Type[]{inputAddress.GetType()});
MethodInfo genericMethod = method.MakeGenericMethod(output.AddressType);

output.AddressList.Add((IAddress) genericMethod.Invoke(null, new object[]{inputAddress}));
}
}

return output;
}

Sunday, 3 February 2008

Hamburg

I have just spent a weekend in Hamburg with my wife, and it was a bit of an eyeopener. I've never visited Germany before (stopovers in airports don't count; if they did I'd consider myself really well traveled indeed) and the surprises were many. For starters the stereotypical German was not to be found. Not a grumpy, angry, or rude person in sight. In fact, the Hamburgers (ha ha!) are as pleasant as they come. Londoners, you've got something to learn here. I also expected people to be very strict and correct - perhaps a little uptight. That wasn't the case, either. Perhaps I've just got a nasty set of preconceptions (and perhaps all of this is evident to all of you) but now all those have been thrown aside and I really cannot wait to come back again. Germany-by-car is now high on the list of priorities.

The thing that touched me the most about Hamburg, however, was the walk through the area around St. Nikolai Memorial - a former residential area that was bombed to smithereens by the RAF and USAF during a true campaign of terror (sorry for using such a watered down and inaccurate term, but just about any historical text deems Operation Gomorrah [yes - that's what they called it] an act of deliberate terror) during the end of July 1943. Over the course of just a few days 35000 civilians were killed. (The wikipedia article cites 50000 deaths, and this Air Force Magazine article cites 40000 deaths, yet the St. Nikolai Memorial quotes the number as roughly 35000.) German civilians were the target of this campaign which aimed to demoralise the enemy. I am not about to get political here, but I think we're quick to forget the sufferings of the German people during the war, and this was a good reminder for me, at least, that even the history of WW2 cannot be drawn in black and white.

The remarkable thing is that Europe, somehow, has managed to pick up the pieces and pull itself back into relative unity. We, the generations born after the war, have so much to be thankful for. When we get caught up in our everyday dramas, disasters or despair, perhaps we ought to stop and spare a moment of thought for what was given and was lost in the war fought to preserve our European liberty. Don't think that your lifestyle is a given, and certainly don't take it for granted. Instead, travel to Germany and experience the country and the people and find yourself among some of Europe's friendliest.

Test Driven Development, part 1.

Testing is central to any software development. We simply cannot live without it and, though its role in the development life cycle is often underestimated, thorough, good, repetitive testing is crucial to delivery of quality software. Testing can be done in any number of ways and is all too often treated as an afterthought at the end of a development project. I want to take some time now and over several posts to speak about Test Driven Development (TDD), a methodology that puts testing at the front, in the driver's seat, of software development.

TDD is certainly nothing new, and there are numerous excellent texts available on the topic. What I will be writing about here has probably been covered in said texts, however I wish to cover the central topics here and highlight things that I have found particularly useful, interesting, or plain difficult. TDD is a huge topic and there are lots of development frameworks available to support the developer (each typically targeting a specific language or group of languages), several streams of thought (classic TDD vs Mocking for example), and multiple ways of achieving the same things. By getting at it piece by piece I hope to form a coherent picture of what TDD is all about and how you can use different frameworks and apply different methods and approaches in a manner that suits you, your business and your project, all in an effort to improve the quality of the software you write.

I think a good approach to this will be to start with fairly coarse-grained topics such as what, why, where, when, and how - though perhaps not in that order. Several subtopics will pop up along the way and I'll address these as I go.

Now, if you are reading this and you are interested, please feel free to post your comments and questions. Here we go...

TDD, What is it?
Test Driven Development is, as the name implies, a methodology for software development in which tests are what drive the actual creation of software. In TDD tests define the software requirements at a level of very fine granularity. TDD is unit testing in action, where a unit is a single public method. (In 99% of the cases you will only ever test public methods, though there are exceptions.)

When we say that a test defines a requirement it means that a test is created to assert that when a certain action is performed (a public method is called) in software, specific results ensue (the state of an object changes in a specific manner). A very trivial example of this could be a Dispenser class that represents a vending machine. The requirement could state that when a can of soft drink is dispensed, the number of cans (of that type of soft drink) is reduced by 1. The test that defines this requirement would create a Dispenser instance with a certain known number of cans (of Fanta, for example) and then call Dispense(typeof(Fanta)) on the Dispenser class. The _actual_ test here is that after the Dispense method has been called the quantity of Fanta cans left must be the initial quantity less 1.

You've probably already asked yourself "what kind of requirement is this?". It's certainly not a very typical requirement you'd ever get from a customer. Instead the customer is likely to define the requirement something like this: When a can of soft drink is to be dispensed, ensure that the customer has inserted sufficient coins, then dispense the correct can of drink according to the button pressed. Ensure that the stock levels are updated and that the customer is issued the right amount of change, if applicable.

In the middle of _that_ requirement you'll notice that there is a reference to stock levels. This corresponds nicely to the test we defined in the previous paragraph. As you can see, a customer's requirements (a functional requirement) typically breaks down into several low-level requirements. This is a good thing, because in order to test efficiently you need to test one condition at a time.

But I get ahead of myself. Let's go back to talking about requirements and how tests represent them. If you stop and think for a while about the client's requirement for dispensing a can of soft drink you'll see that several software components are needed to build the software to control the client's machine. We need software to deal with cash (counting coins and dispensing change), software that controls the machine's input buttons, software that keeps track of stock, software to control the dispensing mechanisms and so on. When you start thinking about how these components will work, and how they will work together, your process of design will quickly move down to a much lower level of requirements and you'll see the smaller elements, the software units that need to exist in order for the machine to work as the customer specifies. All these smaller units have their own very specific requirements that are pieces of, and together form the whole of the customer's high-level requirement.

Describing unit tests and requirements in this way may make it sound like it is easy to deduce what the higher level requirements of a software are based on the low level unit tests. That is usually not the case. At the low level each individual unit (method) is tested to ensure that it behaves as prescribed. This is very useful as it clarifies the intent behind the written code, however as each test is separate to other tests there is no apparent way to string a set of random unit tests together in order to form a more human requirement at a higher level. _Integration tests_ go some way towards bridging this gap but these will be discussed later in a different post as they are likely only to introduce confusion here.

So far we have established that TDD is about testing each unit of code to ensure that it works, it behaves in the manner you, the developer, intended. But TDD is a methodology that does much more than create unit tests. It is certainly possible to unit test code without the TDD approach.

What sets TDD apart from other unit testing methodologies is its focus on testing before and during the development process. You may find it a little strange that testing takes place before development takes place, yet indeed this is a very crucial point. TDD stipulates that you do not write any code unless you have a test for that code. For example, if you need to write a method that adds two integers you must first write a test for that method that verifies its behavior. Your test would for example pass the integer 2 and the integer 5 to the method and expect that the returned integer is 7. You write this test before you write your Add(int, int) method - but of course that test does not compile. But you can now write your method and instantly run your test to verify that it works the way you intended.

Though this is an overly simplified example it still highlights that the tests you write up front are the driving factor for the actual code you develop. Writing software in this manner forces you to think very carefully about what you are doing and what you are trying to achieve. If you do this diligently (I will post about the how of TDD later) you will find that you not only produce code that is very accurate (it does exactly what you intend) - you also produce code that is highly testable (duh!)! Though I will also post about the why of TDD later, it should be evident at this point that code that is easily testable has high value.

That kind of wraps it up for the what of TDD. Next time I'll write about the why.