Wednesday, November 30, 2011

Use screencasts for your bug reports

Note: So finals are about to start, you might not see me for awhile.

Anyway,

On the project I'm on now, we're working directly with the client (the owner of a local business) on a web application. We took over the project from another company working on it and started with some bug fixes. In my experience the most difficult part of tracking and killing bugs reported by someone else is simply reproducing them.

Let's take a look at a bug report style you might have encountered (I certainly have):
Bug: Clicking on the SaveLotsOfMoney button causes the browser to explode

Login as Jim
Click "SaveLotsOfMoney" button
"Server error" is displayed right before the browser explodes and crashes

Attached: a screenshot of the browser exploding. 

Alright, this is actually a good one because at least they stuck a screenshot on it and they were nice enough to enumerate the steps they had taken (as opposed to "it just crashed").

Now you've just taken the project and you have no idea how the code works. So you try and reproduce it, but the SaveLotsOfMoney button works fine for you. Oops?

Turns out the actual problem was that during previous testing the reporter did something unrelated, data was changed, and the guy before you forgot to do a null check and now the browser has exploded. It doesn't happen for you because you're making your tests reproducible (of course).

How do you prevent this? Make them do it again? Now they can't reproduce it! They didn't know that what they did previously affected that test, because it's not their job to know the details, so of course they don't include it in their bug report.

The solution to this that our current client uses is to make screencasts of the bug in action. This is very important, because it means you can see everything that they were doing that caused the bug. It can vary, and in my case it was a detailed error message (a "foreign key violation -- big help") that was shown. In another case I was able to see signs of data they had previously changed, which led to reproducing it.

So: don't use those old crusty bug reporting methods, try making screencasts of them instead. The client mentioned uses a tool called Jing (disclaimer: I don't work for them) to record their screencasts and it looks good to me, though I have no personal experience with it.

Monday, November 21, 2011

Get up to speed on a new project by writing Selenium tests

Alright. So I've taken the task of maintaining and extending an ASP .Net MVC 2 project with a friend of mine. It's not too big, but there are some things working against us:
  • Neither of us have done ASP .Net development before
  • We had to set up a new database (this was actually the hardest part) 
  • There are no tests for the project
  • The javascript looks like our javascript back in the beginning of the Recordings project ... we've learned better since then.
Actually, let me emphasize that last point. I'm a big fan of automated testing, so much that I feel hesitant to modify code that isn't under test (excluding the simple stuff, of course). Especially on an unfamiliar code base. That's why one of the things we've been doing and really emphasizing on this project is automated UI tests with Selenium 2 WebDriver.

Writing tests using Selenium has helped us learn the functionality of the application as well as establish a good suite of tests for future modifications. And at the moment they are more useful than unit testing due to the difficulty of unit testing parts of the code.

In addition, we're making sure to keep our tests nice and clean using PageObjects and also making them reproducible when they mess with the database. Eventually we'll have these tests picked up by our CI server when it builds the project before deployment.

Of course, that doesn't mean we're going to go without unit testing the code. There are a couple static classes from the ASP .Net libraries that are mixed in with areas we'd like to test -- but using some questionable hacks we've been able to work those out. And after burying said hacks in another layer of abstraction, we can write nice clean unit tests like we all enjoy.

So: Now that we're on a new project things should pick up with this blog again. Recordings is live and complete, so there hasn't been much programming for a few weeks.

See you next time, though.


    Monday, November 7, 2011

    Log4net in a not-.NET application

    Hi everyone,

    So I've moved on to a couple of other projects (Recordings is now live and complete enough). One such project is an old legacy VB6 application that I'm extending with C# via COM interop.

    The situation I have is this:
    • I would like to use Log4net in the C# code, compiled as DLLs and imported into the VB6  project
    • I would like to configure Log4net via an xml config file, but it won't have to change at runtime. 
    So, here's how that's accomplished:

    The log4net.config file is added as an embedded resource in the C# class library project. It looks like this:

    <?xml version="1.0" encoding="utf-8" ?>
    
    <log4net>
      <appender name="DebugFileAppender" type="log4net.Appender.RollingFileAppender">
        <file value="J:\Chris\Source\citysiege\main\logs\" />
        <appendToFile value="true" />
        <rollingStyle value="Date" />
        <maxSizeRollBackups value="30" />
        <datePattern value="yyyy-MM-dd'.txt'" />
        <staticLogFileName value="false" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%date [%thread] %-5level %logger - %message%newline"/>
        </layout>
        <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
      </appender>
    
      <root>
        <level value="DEBUG" />
        <appender-ref ref="DebugFileAppender" />
      </root>
    </log4net>
    

    A static class method serves as a wrapper around the log4net library and an entry point to configure it:

                var assembly = Assembly.GetExecutingAssembly();
                var stream = assembly.GetManifestResourceStream("CitySiegeLogic.log4net.config");
                log4net.Config.XmlConfigurator.Configure(stream);

    Simple right? Well, took a little while to figure out. Also, if the config file is in a subfolder be sure to add that to the path along with the namespace, so for example "CitySiegeLogic.logging.log4net" if its under /logging.