Ayende @ Rahien

Unnatural acts on source code

Individuals and Interactions over Processes and Tools

This post from Sam Gentile has made me realize that I need to clarify a few things about the recent TFS vs. XYZ discussion.

This post isn't really aimed at him [that would be me] but I do find a post by him seeming to suggest that you only can use OSS tools to be "Agile" to be, well, quite disappointing

I guess that I didn't notice the conversation digress, but I really should clarify that it has never been my intention to suggest, or seem to suggest, any such thing. Tools helps, and I think that they are important. I have my own preferences, based on my experiance and the way I like to work.

I am mostly talking about OSS tools because I am familiar with them and it makes it easy to point out and show. The best project management system that I have worked with is JIRA, but Trac does quite a bit of the work, and doesn't require as complex a setup.

There is no correlation or dependency between the tools that you use and the way that you work. And you most assuredly can use TFS to be agile.

I do think that tools can be of significant help, you can certainly be agile without them, but it is easier with them. My issues with TFS has nothing to do with agility, and everything to do with seamless usage, a whole seperate issue alltogether.

 

Unit testing with NHibernate / Active Record

One of the more difficult regions to test in an application is the data access layer. It is difficult to test for several reasons:

  • It is usually complicated - fetching data effectively is not something trivial in many cases.
  • It can be highly dependant on the platform you are using, and moving between platforms can be a PITA.
  • It is usually hard to mock effectively.
  • Database by their natures keep state, tests should be isolated.
  • It is slow - we are talking out of process calls at best, remote system calls at worst.

I am a big fan of NHibernate, and I consider myself fairly proficent in mocking, and I find it very hard to mock data access code effectively, and that is when NHibernate already provides a very easy set of interfaces to work with.

The issue is not with calls like this:

Post post = (Post)session.Load(typeof(Post),1);

This is very easy to mock.

The issue is with calls like this one:

Post post = (Post)session.CreateCriteria(typeof(Post))
     .Add(Expresion.Like("Title", title))
     .AddOrder(Order.Asc("PublishedAt"))
     .SetFirstResult(0)
     .SetMaxResult(1)
     .UniqueResult();

Trying to mock that is going to be... painful. And this is a relatively simple query. What is worse are a series of queries, which work together to return a common result. When my setup code crossed the 500 lines of highly recursive mocking just to give the test a reasonable place to work with, I knew that I had an issue.

I could break it up to more rigid interface, but that completely ignore the point of being flexible. The above query is hard coded, but pretty often I find myself building those dynamically, which is not possible using rigid (but more easily mockable) interfaces.Please note that I am not talking about the feasability of mocking those, I have done it, it is possible, if lenghty, I am talking about maintainability and the ability to read what was the intention after six months has passed. Bummer, isn't it?

Then I thought about SQLite. SQLite, despite their documnetations shortcoming, is a lightwieght database engine that supports an in memory database. What is more, NHibernate already supports it natively (which saved me the effort :-) ). SQLite is an in-process database, and in-memory databases are wiped when their connections are closed. So far we removed two major obstacles, the statefulness of the databasess, and the inherent slowdowns we are going across process/machine boundaries. In fact, since we are using entirely in-memory database, we don't even touch the file system :-).

But we have the issue of moving between platforms. We can't just port the database to SQLite just for testing. Or can we?

First, let us define what we are talking about. I am not going to performance testing (except maybe SELECT N+1 issues) on SQLite, this require the production (or staging) database with a set of tools to analyze and optimize what we are doing.

So, if we ruled perf testing from the set of scenarios we are looking for, we don't need large amounts of data. NHibernate will create a schema for us, free of charge, and it can handle several databases transperantly. We don't need to mock anything, it looks like we are golden.

I got the following code:

[TestFixture]

public class InMemoryTests : NHibernateInMemoryTestFixtureBase

{

      private ISession session;

 

      [TestFixtureSetUp]

      public void OneTimeTestInitialize()

      {

            OneTimeInitalize(typeof(SMS).Assembly);

      }

     

      [SetUp]

      public void TestInitialize()

      {

            session = this.CreateSession();

      }

 

      [TearDown]

      public void TestCleanup()

      {

             session.Dispose();

      }

      [Test]

      public void CanSaveAndLoadSMS()

      {

            SMS sms = new SMS();

            sms.Message = "R U There?";

            session.Save(sms);

            session.Flush();

           

            session.Evict(sms);//remove from session cache

           

            SMS loaded = session.Load<SMS>(sms.Id);

            Assert.AreEqual(sms.Message, loaded.Message);

      }

}

Initialize the framework, create a session, and run. Notice that the test doesn't care what it is working against. It just test that we can test/load an entity. Let us look at the base class:

public class NHibernateInMemoryTestFixtureBase

{

      protected static ISessionFactory sessionFactory;

      protected static Configuration configuration;

 

      /// <summary>

      /// Initialize NHibernate and builds a session factory

      /// Note, this is a costly call so it will be executed only one.

      /// </summary>

      public static void OneTimeInitalize(params Assembly [] assemblies)

      {

            if(sessionFactory!=null)

                  return;

            Hashtable properties = new Hashtable();

            properties.Add("hibernate.connection.driver_class", "NHibernate.Driver.SQLite20Driver");

            properties.Add("hibernate.dialect", "NHibernate.Dialect.SQLiteDialect");

            properties.Add("hibernate.connection.provider", "NHibernate.Connection.DriverConnectionProvider");

            properties.Add("hibernate.connection.connection_string", "Data Source=:memory:;Version=3;New=True;");

 

            configuration = new Configuration();

            configuration.Properties = properties;

            foreach (Assembly assembly in assemblies)

            {

                  configuration = configuration.AddAssembly(assembly);

            }

            sessionFactory = configuration.BuildSessionFactory();

      }

     

      public ISession CreateSession()

      {

            ISession openSession = sessionFactory.OpenSession();

            IDbConnection connection = openSession.Connection;

            new SchemaExport(configuration).Execute(false,true,false,true,connection,null);

            return openSession;

      }

}

Here we just initialize NHibernate with an in memory connection string and a SQLite provider. Then, when we need to grab a session, we make sure to initialize the database with our schema. Disposing the session closes the connection, which frees the database.

So far we handled the following issues: Slow, Stateful, Hard to mock, platform dependant. We have seen that none of them apply to the issue at hand. Now, what about the last one, testing complicate data fetching strategies?

Well, that is what we do here, aren't we? In this case, true, we aren't doing any queries, but it is the prinicpal that matters. Looking at a database through NHibernate tinted glasses, they look pretty much the same. And a querying strategy that works on one should certainly work on another (with some obvious exceptions). I am much more concerend about getting the correct data than how I get it.

The beauty here is that we don't need to do anything special to make this happen. Just let the tools do their work. To use Active Record with this approach, you need replace the calls to the configuration with calls to ActiveRecordStarter, and that is about it.

Even though those tests execute code from the business logic to the database, they are still unit tests. To take Jeremy's Qualities of a Unit Test as an example, unit tests should be:

  • Atomic - each test gets each own database instance, they can't affect each other.
  • Order indepenent and isolated - same as above, once the test finished, its database is back to the Great Heap in the Sky.
  • Intention Revealing - throw new OutOfScopeException("Issue with test, not the technique");
  • Easy to setup - check above for the initial setup, afterward, it is merely an issue of shoving stuff into the database using NH's facilities, which is very easy, in my opinion.
  • Fast - It is an in memory database, it is fast. For comparison, running this test on SQL Server (locahost) runs at about 4.8 seconds (reported from TestDrive.Net, and include all the initialization) running it on SQLite results in 3.4 seconds. Running an empty method on TestDriven.Net takes about 0.8 seconds. Most of the time is spent in the initial configuration of NHibernate, though.

Hope this helps....

Testing ASP.Net UI: WATIR Impressions

I've started looking at writing integration tests for an ASP.Net application. I have a farily complex application with quite a bit happening in the UI layer. Some pages are fairly simple data entry forms, and some contains UI that is scary to just think about (the amount of work it would take). It has long been my belief that it is not worth testing the UI layer. A lot of effort goes into this, and it is usually fragile in the face of changes.

The problem is that without tests is it very easy to break stuff, and I get lost in the amount of pages / controls that I have there already. It took a failure (in the middle of a client demo, of course) to convince me that it is not enough to verify changes manually. I'm currently investigating WATIR, and it looks like it is farily simple to work with it once we learn ruby, the API and the quirks.

Current things that I have issues with are speed, state, enconding, controls naming, popups and alerts.

Speed seems to be an issue, so far I have only tested it in interactive mode, but it looks like it takes quite a bit of time to run. Quite a bit of time means that I can see things happening. Looking at the documentation, I noticed such things as -f (fast), so it may be a debug mode slowdown so I could keep track of what is going on.

State is the issue of what is the current state of the application for the test. For instance, I may want to try updating an entity, and this means that it have to exists, or creating an entity when it has a certain parents, etc. This require a lot more thought than just Unit Tests, since in Unit Tests I either mocks the whole infrastructure layer (and it is not fun, trust me), or I nuke the entire DB between tests. Testing it via ASP.Net is more complex, since I have to take into account such things as caching, etc. This make it a more real test case, but make it harder to write the test. Oh well, at least the secretary wouldn't do it.

Enconding may be a problem. This is still a heresay only, but I understand that ruby has issues with unicode. A lot of the texts that I need to verify in my pages is in Hebrew, so this may be a real problem. We haven't run into it yet, but we are just beginning.

Controls naming is an ugly beast in ASP.Net, you get names like this one "ShowArchive1$dgArchive$_ctl3$_ctl0", and they may change very easily. I really don't like to see them in the tests. I think that using indexes to find the controls is just as evil in any case.

Rant: Why on hell WATIR indexes are 1-based?

Popups and alerts seems to be a weak point in WATIR, I couldn't get it to work no matter what I did, and eventually I had to resort to this to get a simple confirm dialog to work. Just so you would understand, this opens a whole new process just to send an OK to the window. There doesn't seem to be any way to get the text of the cofirm/alert window. More worrying is the popup functionality, I can't find a way to handle a modal popup nicely. It looks like I would need two tests there, one to handle the code up to the popup and afterward, and another to handle the popup itself.

Some interesting links about WATIR:

Continious Integration: What about 3rd Party stuff?

I'm now building the CI server, and I'm installing all the neccecary things like cruise control, SDK, NUnit, etc. The question is where do I draw the line? The ideal is to have as little as possible on the CI system itself.

For instance, how should I handle Infragistics' controls?

Tags:

Published at

Testing generated code

A couple of days ago I asked about how to test that code that generates code. Basically, there are two or three options:

  • String comparisions - Fragile, but easiest to do.
  • Use a C# Parser and check the resulting DOM
  • Compile the code and test that

I went with the third option, mostly because it was the easiest to write. I had another project where I tried the strings approach, and I ended up not running the tests because they were so fragile.

Here it the first test that I wrote (the project here in NHibernate Query Generator):

[Test]

public void CanGenerateCodeThatDoesnotProduceErrors()

{

       StringBuilder sb = new StringBuilder();

       TextReader reader = new StreamReader(GetSampleStream());

       TextWriter writer = new StringWriter(sb);

       QueryGenerator generator = new QueryGenerator(reader, new CSharpCodeProvider());

       generator.Generate(writer);

       string code = sb.ToString();

       CodeDomProvider provider = new CSharpCodeProvider();

       CompilerParameters cp = new CompilerParameters();

       cp.GenerateInMemory = true;

       cp.OutputAssembly = "Generated.Context";

       cp.ReferencedAssemblies.Add(typeof(ISession).Assembly.Location);//nhibernate

       cp.ReferencedAssemblies.Add(typeof(NamedExpression).Assembly.Location); // named expression library

       CompilerResults results =  provider.CompileAssemblyFromSource(cp, code);

       Assert.AreEqual(0, results.Errors.Count);

}

After writing this, I compiled and run, and it worked. Empty code appears to compile, so I refactored a bit, moved things to the Setup and util methods (CompileCode(), AssertCodeCompiles() and GetAssemblyFromCode).

Then, it was time to write a meaningful test, like this one:

[Test]

public void GeneratedAssemblyHasWhereTypeWithNestedCustomerType()

{

    Assembly asm = GetAssemblyFromCode();

 

    System.Type whereType = asm.GetType("Query.Where");

    Assert.IsNotNull(whereType, "Should have gotten an assembly with a where type");

 

    PropertyInfo customerProperty = whereType.GetProperty("Customer");

   

    Assert.IsNotNull(customerProperty, "Where type should have property Customer");

}

Since I have compilable code, I can use Reflection to verify that I generated the code that I wanted. From there, it was a simple matter of writing a test using Reflection, and then writing the code that would generate the expected output.

An ORM is NO excuse to violate the Single Responsability Principal

This post is directed at yours truly. Take a look at this class:

(Image from clipboard).png

The ISessionManager interface is provided by Windsor NHibernate Integration, it gives me an access to NHibernate's ISession, which in turn gives me an access to the database.

It is really easy to write code for this system, you pull some stuff from the database, minor processing, and it is done. It is testable, because you are using only interfaces. The problem is with the ease of testing. I couldn't quite put my hand on why my tests were cumbersome to write.

Take a look at this snippet:

[Test]

public void LogErrorIfFileHasNotArrived()

{

    MockRepository mocks = new MockRepository();

    ISessionManager sessionManager = GetSessionManagerAndSetupMocks(mocks, new ArrayList());

Where GetSessionManagerAndSetupMocks is defined:

 

private static ISessionManager GetSessionManagerAndSetupMocks(MockRepository mocks, IList list)

{

    ISessionManager sessionManager = mocks.CreateMock<ISessionManager>();

    ISession session = mocks.CreateMock<ISession>();

    ICriteria criteria = mocks.CreateMock<ICriteria>();

    Expect.Call(sessionManager.OpenSession()).Return(session);

    Expect.Call(session.CreateCriteria(typeof (FileState))).Return(criteria);

    Expect.Call(criteria.Add(null)).IgnoreArguments().Repeat.Twice().Return(criteria);

    Expect.Call(criteria.List()).Return(list);

 

    session.Flush();

    session.Dispose();

    return sessionManager;

}

And that is for a fairly simple test. This creates an environment where it is pretty hard to write the tests, because I need to setup quite a bit of code, and it has to be intimately familiar with the structure of the class under test. I am dealing more with infrastructure than with testing something that adds a real value.

I am currently refactoring all the usages of ISessionManager (and NHibernate) to satallite interfaces/classes, which allows me to transform the above test to this:

[ Test]

public void LogErrorIfFileHasNotArrived()

{

       MockRepository mocks = new MockRepository();

       ICheckFileArrivedDataHelper dataHelper = mocks.CreateMock<ICheckFileArrivedDataHelper>();

 

       MemoryAppender appender = new MemoryAppender();

       BasicConfigurator.Configure(appender);

 

       Expect.Call(dataHelper.GetFilesNotMarkedByWatcher(3)).Return(new FileState[0]);

 

       mocks.ReplayAll();

 

       CheckFileArrivedTask fileNotArrivedTask = new CheckFileArrivedTask(dataHelper, 3);

 

       fileNotArrivedTask.Execute();

 

       LoggingEvent loggingEvent = appender.GetEvents()[0];

 

       Assert.AreEqual(Level.Error, loggingEvent.Level);

 

       string msg = @"File type: 3 did not arrived in its period!";

 

       Assert.AreEqual(msg, loggingEvent.MessageObject);

 

       mocks.VerifyAll();

}

The part in large font replaced all the code in GetSessionManagerAndSetupMocks. Now the intent of the test is much clearer, and it is far easier to test this stuff. I no longer have to match every little thing that is going on there, instead, I can focus on the bigger picture.

I still need to test the implementation of the data helper, but that can be done in the integration tests.

TDDing Log4net

I have an application where logging is a business concern.
Usually, logging is something that I do so I could remotely debug the application, or have a better understanding of what is going on. This is the first time where the logs are actually something that is a business concern.
I usually don't tests logging, so I wasn't sure how to start. I probably should mention that I am using log4net for the logs.

After searching a bit, I found that it is really simple:

[SetUp]
public void TestInitialize()
{
    _memoryAppender = new MemoryAppender();
    BasicConfigurator.Configure(_memoryAppender);
}

And then, in the tests, all you need to do is:
LoggingEvent[] events = _memoryApender.GetEvents();
And start asserting.

Strangely, the best place to read about log4net strengths is here, in the comments for a blog post (check the second comment by Ron Grabowski).

Do NOT Mock System.Data.*

While it is possible, it is a pain in the ass. I'm working on a project now that doesn't use NHibernate (yes, I am surprised too).

There is very simple data acess there, and nearly nothing to do with touching the data, so I thought that I could simply use ADO.Net. It works, sort of, but my code is full of strings, and it is nearly untestable. The main issue is that all the *DataAdapter expect their own *Command, *Connection, etc. Which mean that I can't mock much of it.

Check out this little piece of a test (part of about 50 lines of setup, that leads to two lines of real test.

MockRepository mocks = new MockRepository();

IDbConnectionProvider connectionProvider = mocks.CreateMock<IDbConnectionProvider>();

IDbConnection connection = mocks.CreateMock<IDbConnection>();

IDbCommand getRecordsCommand = mocks.CreateMock<IDbCommand>();

ISender sender = mocks.CreateMock<ISender>();

SetupResult.For(connectionProvider.Connection).Return(connection);

IDbCommand deleteItems = mocks.CreateMock<IDbCommand>();

IDbDataParameter dataParameter = mocks.CreateMock<IDbDataParameter>();

IClock clock = mocks.CreateMock<IClock>();

SetupResult.For(clock.Current).Return(new DateTime(2006, 12, 20, 22, 45, 33));

 

connection.Open();

Expect.Call(connection.CreateCommand()).Return(getRecordsCommand);

 

string spToGetItems = "GetLockedRecords";

string spToDeleteItems = "DeleteItems";

getRecordsCommand.CommandText = spToGetItems;

getRecordsCommand.CommandType = CommandType.StoredProcedure;

getRecordsCommand.Dispose();

I could do the same with NHibernate in about three lines, and that would be easy. I'm considerring ripping what I already have and going that route. It would certainly be easier.

Don't Discuss, Implement

This is just to vent a personal frustration. There is nothing really new or innovative here.

Recently I've been spending a lot of time talking about a specific feature about how it should be implement and what the concerns should be and how it should be handled, etc. The sad part is that I could have implemented the feature and get working code in about one third of the time that it took to discuss the issues.m

Tags:

Published at

Leave a failing test

Dave is making the case for leaving a failing test for yourself when you finish for the day. This way you come back tomorrow, run the tests, get the failure, and have a starting point for the day.

I used this technique before several times, with varying levels of success. It only works if you write the test, see it fail and leave immediately afterward.

He also mentions that you sub-conciousness will work on it during the night, which I'm not sure I like. I think about computers too much as it is... :-)

NUnit 2.4 Alpha

Halleluja! Check out the release notes for NUnit 2.4. Here are the things that I'm excited about.

  • Can install by non administrators
  • CollectionAssert - At long last, we have it. I can't tell you how often I wanted those asserts. And check out the methods that this has.
    • AllItemsAreNotNull
    • AllItemsAreUnique
    • Contains
    • IsEmpty
    • IsSubsetOf / IsNotSubsetOf
  • File Assert with support for steams!
  • App.config per assembly

The most important thing is that they have (finally) setup / teardown at the assembly level! This is a huge deal for me, since I write a lot of applications that require initial state, and then I need to remember initializing it in the setup of each test.

They also have support for setup / teardown per namespace, which is really strange.

This is looking really cool.

Tags:

Published at

A Story About Testing In Multi Threaded Environments

I just finished a really nice project that involved heavy use of multi threaded code. The project is enterprisey (which has turned into a really bad word recently, thanks to Josling and The Daily WTF), so I needed to make sure that I was handling several failure cases appropriately.

Now, testing multi threaded code is hard. It is hard since you run into problems where the code under test and the test itself are running on seperate threads, and you need to add a way to tell the test that a unit of work was completed, so it could verify it. Worse, an unhandled exception in a thread can get lost, so you may get false positive on your tests.

In this case, I used events to signal to the tests that something happened, even though the code itself didn't need them at the beginning (and didn't need many of them at all in the end). Then it was fun making sure that none of the tests was going to complete before the code under test ( there has got to be  a technical term for this, CUT just doesn't do it for me ) has completed, or that there were no false positives.

As I was developing the application, I run into issues that broke the tests, sometimes it was plainly bugs in the thread safety of the tests, and I could see that the code is doing what it should, but the test is not handling it correctly. I was really getting annoyed with making sure that the tests run correctly in all scenarios.

In the end, though, I was just about done, and I run the tests one last time, and they failed. The error pointed to a threading problem in a test. It was accessing a disposed resource, and I couldn't quite figure why. Some time later, I found out that an event that was supposed to be fired once was firing twice. This one was a real bug in the code, which was caught (sometimes it passed, the timing had to be just wrong for it to fail) by the test.

Actually, this was a sort of an accident, since I never thought that this event could fire twice, and I didn't write a test to verify that it fired just once. (In this case, it was the WorkCompleted event, which was my signal to end the test, so I'm not sure how I could test it, but never mind that.)

I spent some non trivial time in writing the tests, but they allowed me to work a rough cut of the functionality, and then refine it, knowing that it is working correctly. That was how I managed to move safely from the delete each row by itself to the BulkDeleter that I blogged about earlier, or to tune the consumers, etc. That final bug was just a bonus, like a way to show me that the way I used was correct.

Now, the tests didn't show me that if I try to shove a 30,000 times more data than it expected, the program is going to fail, that was something that load testing discovered. But the tests will allow me to fix this without fear of breaking something else.

Tags:

Published at

Rant

Note: This post started as a comment on the post just below, but it developed into a full blown rant along the way. I'm detailing many of my frustrations with the tools.

Scott Bellware has posted Mort or Elvis? A Question for a Bygone Era, which is a great post (as usual), but it also hit many of the pain points that I feel in working with VS 2005 recently. In fact, Scott does a great job of expressing those pain points than I could.

Microsoft's tools are getting progressively worse rather than better.  Microsoft development tools are showing the unmistakable signs of entropy and neglect that comes as a result of the parasitic infestation of product development groups by the cowardly side of the software business.... 

In the comments he talks about Microsoft's tools and then subtle product placement that I didn't recognize but drive me constantly crazy. I use VS.Net 2005 for the simple reason that it is the only one out there for .Net 2.0 development. ReSharper makes the job bearable, but it says quite a bit if I need an alpha quality tool just to feel good again.

Beyond VS.Net, my most common tools are not Microsoft ones (NAnt, NUnit, TestDriven.Net, etc). Scott comments on this:

And indeed, these folks [thinking developers] will bring an arsenal of better tools to the table.  Few of them will have been created by Microsoft, and most of them will be free, and open-source. 

Finally, there is this sentiment that I agree with wholeheartedly:

I would pay right out of my own pocket for a .NET IDE built by JetBrains. They could change me $1000 and I'd be delighted to fork over the cash if they could give me an IDE that was file-system and project-system compatible with Visual Studio with none of the bloat and none of the endless, insulting product placement clutter that has gained influence over the design of Visual Studio to the detriment of good, clean, usable product.

I wanted this for a long time. I hope that once they release ReSharper, they will rev up the work on .Net IDE. I know that I would buy Intelli.Net IDEA in a heart beat, and push it out as far as I can.

And now to my own ranting:

And my own note about the personas. They don't work anymore. I get questions from VB.Net developers that want to know how to use Rhino Mocks, there have been questions about VB.Net development with Castle, etc.(Not to go down on VB.Net programmers, but this is the language that is portrayed as Mort's favoriate). I has to do some UI work right now, and I tried hard to do this with VS.Net's Automatic UI & Coffee System(TM), but I couldn't make it do what I wanted, and I ended up doing most of it manually.

Simple UI should be the part where the tooling is excellent, but in order to use them, you need to know quite a bit about the tools, and that is not something that I see as highly productive. I know the WinForms (and Win32) API well enough to produce a working UI for most of everything, but I don't see investing time in learning the exact incantations that I need to do this or that (nothing highly complicated, by the way) for non standard scenario (binding Business Objects to a form).

By concentrating so hard on the tools, only the supposedly core scnerios are taken care of, leaving everyone that does something different high & dry. And the problem seems to be that there isn't any improvement along the way in the tools.

We have the Web Application Project, to get back the stuff they took away from VS 2003, but that is about it. Where is the promised Service Pack for Visual Studio 2005? I haven't even heard a whisper about it since it was announced, and it is not like there aren't bugs that need fixing in there.

Posts like this one, talking about how features are planned for VS, just scares me. It looks very much like the merit of a feature is its demo-ability. This produce software that demos great, but that just doesn't stand on its own when you need to develop a real scenario. Combine the non-tirivial time that you need to invest to learn how to work with the tool with the even more significant time to learn how to by-pass the tool, and you get a net loss situation. Non-demoable features end up being more important in the long run.

How many demos has seen the demo about File.ReadAllText() method? Yet it ends up saving me 5 lines of code every time that I need to read a file. Or the GC improvements? Or ASP.Net Build Providers? Linq will be cool if I could get a compiler support and intellisense alone. No need to build any UI on it, it is cool because of what it is, not because of what kind of UI I can show in a keynote.

I really like the framework, from ASP.Net to WinForms to Theards to ADO.Net. I just dislike the tool that I have to interact with it. It is nice and shiny from the outside, but don't take a too close look at the support beams. The IDE shouldn't try to help me. I know what I'm doing, thank you very much. I want to be able to work with code in my IDE, intelligence on the part of the IDE is required, otherwise I can just work in Notepad. I don't want to work like Microsoft thinks I should (TDD or DataBinding, for instance), I want to have the functionality in the class library, and the IDE should support it.

I get a far better value from TestDriven.Net than I do from VS' Test Tools, and TestDriven.Net has a far more primitive interface, with far less functionality, probably. But this is a zero friction tool, I don't need to adhere to Jamie's design philosophy if I want to use it.

Okay, that is enough ranting for now, I think

On Comments, Yet Again

After making such a point about commenting being mostly noise, and that code should be able to stand on its own, I found myself adding the following comment (related to this issue) to Rhino Mocks.

//This can happen only if a vritual method call originated from 
//the constructor, before Rhino Mocks knows about the existance 
//of this proxy. Those type of calls will be ignored and not count
//as expectations, since there is not way to relate them to the 
//proper state.
if(proxies.ContainsKey(proxy)==falsereturn null;

There is just no way that I'll remember in 2 week (let alone months) why this is important. Then again, the test for this piece of code is called "MockClassWithVirtualMethodCallFromConstructor", so this should probably be good enough.

Damn, but I love to work on code that is covered with tests. It was a ten minutes affair from getting the test to fail to finding exactly where the problem is, and then it was a simple matter of escelating the call stack until I had a good enough view on what was happening. Two lines of code (and 5 lines of comments) later, I got a passing test.

Three minutes afterward, I was uploading a new release to the website. This is the best thing about doing TDD, I know that I can't break the system without knowing about it. And if I do break something that I don't have a test for, well, if I don't have a test for it, then I'm probably not going to need it after all, so it wouldn't bother me. Perfect :-)

Test Driven Development Is About Failing

This post has nothing to do with Rocky's comments on DNR

I was testing using NHibernate in ways that I never did before*, and the test kept failing. Each time I would fix one thing, and another part would break. It wasn't very obvious how to make it work. I had a guy watch over my shoulder while I worked throught the kinks of the problem. After the test failed repeatedly for the 10th time or so he just muttered something about "never making it work right" and walked away to do something else.

To me, TDD is all about failures. I know that I need to do something only when I get a failing test. And the failing test kept pointing me to this error and that error, and I kept researching and fxing the errors. Eventually I had enough understanding of what I was trying to do and how NHibernate was trying to accomplish it that I could get it to work (perfectly). All in all, it took about 30-40 minutes of trying.

I am not upset to see failing tests, they are the best sign that I have that something is wrong.

This is a Failing Test.
There are many other tests, but this one is a Failing Test.
My Failing Test directs me where I need to be going.

* Highly complex schema with some indirection thrown in to add to the mix.

Rocky Lhotka on TDD, Take #2

Rocky took the time to clarify his comments on TDD in dotNetRocks #169. There seems to be a couple of main points there:

As a testing methodology TDD (as I understand it) is totally inadequate... ...the idea that you’d have developers write your QA unit tests is unrealistic

TDD is not a QA methodology. TDD is about designing the system so it is easy to test. This makes you think about what the code does, rather how it does it. The end result is usually interfaces that are easier for the client to work with, coherent naming for classes/interfaces/methods, the level of coupling goes down and the cohesion of the system goes up. Then you run the test.

The idea in TDD is not to catch bugs (although it certainly helps to reduce them). The idea is to make sure that developer think about the way they structure their code before they start writing it. It also means that developers has far more confidence to make changes, since they have a test harness to catch them if they break something.

And it was pointed out on Palermo ’s blog that TDD isn’t about writing comprehensive tests anyway, but rather is about writing a single test for the method – which is exceedingly limited from a testing perspective.

You start with a single test, to check the simple case, then you write another test, for a more complex case, etc. The purpose is to assert what you are going to do, do it, and then verify that it does what you assrted it should. QA isn't going away in TDD, for the reasons that Rocky mention in his post (developers rarely try to break their app the way a Tester does). QA and Developers takes two different approaches. When I get a bug from QA, I write a failing test for this bug, and then I fix it. Now I got a regression test for this bug.

When I touch this part in 6 months time, I can do it with confidence. I know that I will not:

  • Break any of the assumtions of the original developer - I got tests that verify that the original functionality works
  • Regress any bugs that were found before - I got tests that would verify the bug is fixed.
  • Any future maintainer of the code will not break the sutff I'm doing now - I write tests that will verify that the new functionality is working.

Those and clear design are the main benefits fo TDD, in my opinion. Again, I agree that this doesn't remove the need to have QA team that hates the product and really want to break it :-).

I don't buy into TDD as a “design methodology" either. You can't "design" a system when you are focused at the method level. There’s that whole forest-and-trees thing... ...But frankly I don’t care a whole lot, because I use a modified CRC (class, responsibility and collaboration) approach.

CRC is cool, I agree, but the issue is how detailed you go. I can probably think of the major classes that I need for a project up front, and maybe even come up with their responsabilities and some of the collaborators. Until I sit down with the code, I can't really say what methods and what parameters will be at each class, what other stuff I need to do this work, etc. TDD is about the interface/class/method design, not directly about full system design (although it will influence the system design for sure).

And as long as we all realize that these are developer tests, and that some real quality assurance tests are also required (and which should be written by test-minded people) then that is good.
None of which [developer tests and QA tests], of course, is part of the design process, because that’s done using a modified CRC approach.

This is something I really do not agree with. If you don't use TDD to influence your design, you are not doing TDD, period. You may have tests, but it's not TDD. Writing tests after the fact means that you don't get to think about what the client of the code will see, or use things that make it much harder to test the class. You lose much of the qualities of TDD.

What you end up with is a bunch of one-off tests (even if they are NUnit tests, mind) that doesn't cover the whole system, and are only good for testing very spesific things. They don't affect the design of the code, which can lead to very cumbersome interfaces, and they don't cover the simple to complex scenarios. They may represent several hours (or days!) of programming effort that culimate in a long test that test very spesific scenario. Those are integration tests, and while they have their place, they are not Unit Tests. NUnit != Unit Tests.

And here is a reply to some of the comments in the post:

Sahil Malik commented:

TDD does_not reduce your debugging time to zero. You do end up with an army of tests to maintain. Since the tests are written by and maintained developers, you cannot go with the assumption that the tests themselves aren't bug free. So you write tests to check your tests? Inifinite loop.

You do not stop debugging, that is correct. It does mean that you have a very clean arrow that points to where it failed, including the details, so you have much easier time to fix it. And having an army of tests to maintain would be bad if they didn't have an army of code that they test. Yes, tests has bugs, and the code has bugs, but the chance that you would get the exact same bug in both the test and the code is not very high. When you will see the test fail, you'll investigate and discover that the code is correct and the bug is in the test. No need to write TestTheTestThatTestTheTest... scenario.

Testing UI - A Challange

Here is the story:

When the a node in the graph is hovered via the mouse, a connection point (a node can have several) is made visible, and the user can drag the connection point to another node (when it enter the second node, the second's connection points will be visible) and create a connection between the two connection points. A visible line should exist when dragging the connection, and after it was attached it should be permenantly visible.

I got this to work without tests, since I just can't think of how to test this stuff. Right now I'm heavily using the functionality that Netron provides (which does 96% of the above) and the implementation uses windows events and state tracking quite heavily to get this functionality.

I suppose I can try to refactor the logic out so it would be testable, but that would mean duplicating the events structure for WinForms. In addition, I can see no way to test that the correct stuff is drawn to the screen and I am not fond of taking a screen shot and then comparing the known good to the result on a bit by bit basis. If for no other reason than that I can think of several dozens of tests for the functionality that I need.

Any suggestions on how to test this?

Testing the unknown


I set out today to write something that I never did before, but which I thought was too small to deserve a true spike. I'm talking about my persistance to code implementation, of course.
I started by writing the following test:

[Test]
public void SaveEmptyGrap()
{
    Graph g = new Graph();
    StringWriter sw = new StringWriter();
   
    g.Save(sw);
   
    string actual = sw.ToString();
    Assert.AreEqual("??",actual);
}

I had no idea what I was going to get, but I went ahead and played with the code until it compiled, and then I looked at the result, verified that it was correct* and used that as the expected value.
I could then move on to the next test, graph with nodes, using the same method.

* Just to note, it turned out that I missed putting the method name in Code Dom, which meant that my expected string were wrong. I found out about that only when I tried to load the graphs again. It wasn't hard to fix, but I wanted to point out that this method has its weak points.

Testing as a motivation


There has been a lot said about testing and their affect on the code. I just had the tests affect me as I write the code. You are probably aware that I started a new project recently, and I've (as always) taken my time with a lot of spiking on the design.
Even when I am spiking, I feel very nervous without the tests, and because I'm making such profound changes to the application, there are long stretches of times when I can't even get the application to compile.
This mean that thinking about something and seeing it fail (and it always fails the first time) takes very long time. It also means that I waste quite a bit of time in going the wrong direction.

Today was the day when I finally settled on the design that I would have, and started sweeping thorugh the code, looking for stuff that needs to be tested. I think about this an un-legacifying the code that I wrote this past week (which had only two tests, one of them 40 lines long, yuck!).
I added a lot more tests, renamed a couple of methods, applied the Law of Demeter and voila, I got a code base that is a pleasure to work with.
Then I could start writing features using TDD, and get the rapid feedback that I crave. I actually added value today, which is a great feeling to have in the end of the day.

On Starting a Project and Design Bugs

The part that I hate the most about a project of a type that I never done before is the start. The issue is that I produce a design that mostly works, but when new stuff need to be implemented, I often need to explore several approaches before I know what will work for this project, my last post in an example of the approaches I thought about for persisting object graphs.

The thing that really bothers me is that changing those approaches can lead to major changes in the code. This means that there are extended periods of time that I can't even build the code successfully (30 minutes to an hour, at times). This makes me very nervous, but I don't see how I can avoid doing this as I study the various ways to implement this functionality. In this case, the changes involved changing an interface that was common to many classes in the project, so that caused quite a bit of pain until I settle on the correct approach.

I was at the Israel User Group meeting today and talked with Justin who termed this as a "Design Bug". I like this term. The only encouraging part is that after the initial pain I get a stable base to work from. The bad part is that the changes are big enough that I can't really test drive them beyond very big tests (save the object graph and then load it, for example). Those type of tests are more integration oriented than developer oriented. They help me define the big goal, but not how I get there.

I guess that this is why XP has Spiking for unknown functionality. I'm pretty sure that I'm commiting horrendous crime for doing this with code that will go to production, but in this case, I don't have much implemented yet (only some interesting graph output functionality), so I feel that it is safe to do this.

One thing that I noticed happening is that I lose abstraction along the way. For instnace, when I tried XML Serialization, it couldn't handle interfaces, so I changed several interfaces to abstract classes. When I realized that XML Serialization would probably not work, I revert the changes. For now, I'm seeing this as removing premature abstraction on my part, and if I need this functionality later, it wouldn't be a problem.

Tags:

Published at

The Value Of Reuse

Hammet has posted a comment from his article about Castle. The comment basically talks about reuse in NVelocity, one of the MonoRail's View Engines.

NVelocity is not a full fledge programming language, and that means that you can't do some things that you can do with a full langauge (at least not easily). The end result is that you really don't want to write TheUberGrid in NVelocity, so you may end up writing a one-off, per scenario template, instead of a general control that can accept anything you throws at it and is infinitely more configurable.

Surprisingly enough, or maybe not, the one-off effort usually pays better dividends in terms of the amount of effort involved to get what you need. There is quite a bit to say about specialized solutions to those problems. I had an UberGrid myself, and in order to add a new datatype, I need to edit a dictionary of type > parsing delegate. Sure, it can handle everything from enum localization to showing descriptive text of every object in the system. But I dread the day that I'll have to display the same object in two different forms, since that is not supported, and will require major re-writing.

We're using this UberGrid quite a bit, and it's... nice. But it doesn't really gives us anything. I still code the template per page, setting all the parameters, ordering, etc. It would be just as much work to do it in place, and there wouldn't be any duplication of effort or code. More and more, I'm leaning toward simpler solutions, rather than complex ones.

On the surface, the simple solution may not have all the quantities to do interplanetary navigation (which I don't relish doing in NVelocity), but I find that more often than not, I don't need to do this kind of stuff in those scenario. Good design will keep duplication away, but it shouldn't, and mustn't be at the cost of additional complexity or abstraction.

One off solutions, to one off scenarios are not to be discouraged. When you get the second duplicate scenario, then it is time to start worrying about reusing staff. And because you already got a working implementation, it will be much easier.

Taking Rules to Court

It's about time I'll post about my trouble making rules again. I've been doing some DATT* work on them, and I got to the point where I can write a rule in an hour or so (including tests, of course), instead of a day.

Partly it is because I'm now using Fitnesse to write the tests, which allows for a very nice way to declare rules and various states and then test them. I'm not sure if the problem is with what I'm doing or the way I'm doing it, but when I wrote the tests in C# I got a lot of tedious initialization code, one method call, and a lot of verfication code. Using Fitnesse I'm able to express that in a natural syntax:

create rules
create employee ayende
add employee rule coffee breaks every 3 hours

coffe break
employee coffee break time
ayende 13:00
ayende 14:00
ayende 17:00
ayende 20:00


validate employee ayende
can't take a coffee break on 14:00, take another on 16:00
what are you doing working on 20:00, go home!

It takes about ten minutes to write that, including the code that makes it run, and it's very malleble to change, so I can very easily create new test cases, or modify existing one. Fitnesse is usually used for acceptance tests, and I can certainly see why. The problem in testing rules is that almost by defination, they are first and foremost business concerns, and they usually need something to run on, which mean a lot of state to setup.

There are some patterns about dealing with that, but I found that Fitnesse is easy and add a lot to the fun. This week the FitLibrary for .Net should be out, which will make it even better.

* Design All The Time

New Rhino Mocks release

Well, it's been a while since the daily release cycles, but I've another release out, 2.4.1

This one adds the ability to mock abstract classes. It's strange, but until today I recieved no requests about it.

This release also comes with a custom version of Dynamic Proxy. Usually you won't have to worry about that, unless you intend to hack Rhino Mocks, and so far it doesn't seems like it would be neccecary.

Oh, the download is in the usual place.

Starting With Baby Steps

For me, the hardest part about software project is not quite the beginning, but what follows after. In the beginning, you need to work how to start the project, what is the environment you're going to work with, what is the data access strategy is going to be, etc. 

If you're an Agile practitioner, you're going to start out not knowing where you'll go. It may lead you to and fro as you discover the architecture of your system. I really don't like this part, since you're working hard, producing a lot of things that you'll need later, but you are still too early to get something meaningful going.

In my current project I started out by just mapping out my data acess strategy and implementing CRUD functionality for the basic building blocks. From there, you can start implementing most of the features of the system. But you can't do its heart yet.

Some software systems are all about CRUD, takes Blogs for example. But most applications, while using CRUD heavily, need an extra spark to be useful. A payroll system is mostly about CRUD. You add a worker, add a salary, and that is about it (yes, gross over simplification, I know). The interesting part usually happen behind the scene, and has little to do with CRUD per se. I'm at this point right now, I'm mostly over the routine database access stuff, although there are some pitfalls that I still need to thread carefully by.

What I've to do now is to give the system its heart. That extra something that you can't do in an Excel sheet, if you please :-). And that is the most frustrating part of the work as far as I'm concerned. I'm building blocks that will be useful at a later stage, but too many blocks are missing to get any real functionality. It's a problem because you can't really see what your efforts have given you. I find it maddening, and it's going to be another week at least before I've enough functionality to start combining it in interesting ways.

Tags:

Published at