# Thursday, February 10, 2005
NUnit Stands the Test - Follow up

Patrick Steele made a good point about my last post on Unit Testing. The code that I wrote just happened to use the Test keyword at the beginning of each of my methods. That’s not required. I just happed to like that convention because it reads well.

I do use the attributes and encourage everyone else to because, as Patrick also points out, TestDriven.NET and other tools don’t use it.

Look for another article on TestDriven.NET early next week.


Articles | Development
Thursday, February 10, 2005 7:33:23 PM (GMT Standard Time, UTC+00:00)  #  Comments [0] 

# Tuesday, February 01, 2005
NUnit Stands the Test

Unit testing is only enjoyable and productive with the right toolset. NUnit is the foundation of this toolset. It is a unit testing framework for any .NET language.

NUnit leverages Reflection and Attributes to dynamically discover and execute your tests. The structure of a NUnit unit test is as follows.

Imports NUnit.Framework

 

<TestFixture()> _

Public Class DemoTests

    <Test()> _

    Public Sub TestGetIntegerFromConfigFile()

        'Some code that tests the desired functionality

    End Sub

End Class

 

You add the TextFixture attribute to notify NUnit that a class is a suite of tests. You add the Test attribute to mark a method as a single test case. You can have as many tests in a given test fixture as you want and as many test fixtures in a project as you want. The class that is the TestFixture has to be public and have a default constructor so that NUnit can use reflection to dynamically instantiate it. The methods decorated with the Test attribute have to be public, not take any arguments and return no values (Sub in VB.NET and void in C#) for the same reason.

The next step is to write the code that tests the desired functionality. It’s best if the tests are fairly straight forward and simple.

    <Test()> _

    Public Sub TestGetIntegerFromConfigFile()

        Dim demo As VBDemo.Demo = New VBDemo.Demo

        Dim result As Integer = _

            demo.GetFromConfigFile("MyValue", 0)

 

        Assert.AreEqual(1, result)

    End Sub

 

Assert.AreEqual is the really crucial bit of code from this test. This is one of several types of assertions. An exception of type NUnit.Framework.AssertionException is thrown if one of the assertions fails.

Assert.AreEqual(value a, value b)

Tests if b is equal to the expected value a

Assert.AreSame(reference a, reference b)

Tests if two references point to the same object in memory

Assert.IsFalse(Boolean)

Tests if the Boolean is False

Assert.IsTrue(Boolean)

Tests if the Boolean is True

Assert.IsNull(reference)

Tests if reference is Null as expected

Assert.IsNotNull(reference)

Tests if reference is something as expected

More complex tests can be accomplished with normal if statements and the Assert.Fail method.

If (Not SomeReallyComplexStatement) Then

   Assert.Fail()

End If

 

The code that this test exercises takes the name of a configuration setting and a default value. It will return the value from the configuration file or the default value. The test above assumes that the configuration file has a value as follows.

<configuration>

    <appSettings>

            <add key="MyValue" value="1" />

    </appSettings>

</configuration>

 

A small thing that I’ve discovered is that it’s helpful in cases where there is a config file that the tests are in a console application because VS.NET will manage the app.config automatically for you. In addition, if your tests are in a console application, they could be self sustaining and run whether someone has a NUnit test runner, like NUnit GUI, installed or not. You would have to call the tests from the Main of your console application. You know that the test failed when if there is a NUnit.Framework.AssertionException thrown. I have found that this is helpful in a “Clean” environment where developer tools are not allowed.

If the code is as follows.

Public Class Demo

    Public Function GetFromConfigFile( _

            ByVal settingName As String, _

            ByVal defaultValue As Integer) As Integer

 

        Return defaultValue

    End Function

End Class

 

And you run the test; the result will be as follows.

This is expected. Now you need to fix the code so that it will not result in a red bar.

Now modify the function as follows.

    Public Function GetFromConfigFile( _

            ByVal settingName As String, _

            ByVal defaultValue As Integer) As Integer

 

        Try

            Dim reader As System.Configuration.AppSettingsReader = _

                New System.Configuration.AppSettingsReader

 

            Dim resultAsObject As Object = _

                reader.GetValue(settingName, GetType(Integer))

 

            Dim result As Integer = _

                Int32.Parse(resultAsObject.ToString)

 

            Return result

        Catch ex As System.InvalidOperationException

            'Either the value didn't exist or it was not an Int32

            'Fall through to the default value below

        End Try

 

        Return defaultValue

    End Function

 

Once it is, you are rewarded with a green bar as follows.

Since the normal path is working, you need to test the alternative paths as follows.

There are a number of alternative paths that we can investigate. You can pass in garbage, Nothing (or null in C#), the name of an item that’s not an integer and so on. You could decorate the method with an additional attribute, ExpectedException, if we expected this code to throw an exception rather than handle all of its exceptions. For this example, you simply need the non existent config value and the non integer config value cases.

    <Test()> _

    Public Sub TestGetIntegerFromConfigFileNonExistant()

        Dim demo As VBDemo.Demo = New VBDemo.Demo

        Dim result As Integer = _

            demo.GetFromConfigFile("MyNonExistantValue", 0)

 

        Assert.AreEqual(0, result)

    End Sub

 

    <Test()> _

    Public Sub TestGetIntegerFromConfigFileNotAnInt()

        Dim demo As VBDemo.Demo = New VBDemo.Demo

        Dim result As Integer = _

            demo.GetFromConfigFile("MyNotAnIntValue", 0)

 

        Assert.AreEqual(0, result)

    End Sub 

Now you have a well tested function and tests that can be run over and over again.

We have covered the basics of setting up a unit test with NUnit. There are more features that we will cover in a future post. These include the ability to specify setup and teardown methods, categories of tests and suites of tests.

The code for this post can be downloaded below. It does require NUnit.


Articles | Development
Tuesday, February 01, 2005 2:35:12 PM (GMT Standard Time, UTC+00:00)  #  Comments [0] 

# Monday, January 17, 2005
Unit Testing Rocks!

I was skeptical about the benefits of Unit Testing, like many developers I work with. I work with a lot of development teams as a teacher and trainer. I’d seen some teams benefit, but others got nothing but headaches. My latest project has me convinced that rigorous automated Unit Testing is a software development best practice. It saves time, and enhances your ability to create great software. Let me share my experiences on a large ongoing project. It convinced me, and I think it will convince you too.

We introduced unit testing on my current large project, a change from my previous project. Comparing the progress of the two projects has sold me on its benefits. We are several months in and well past the point that I can keep all but the high level architecture in my head at one point in time. The typical scenario on past projects was that I would write some amount of code, one to fifteen lines of code and run the project. I have often included a button on forms that would fill out all of the fields with the minimum required data to speed up the manual testing process. Right here was one issue – I was putting testing code into the production application. The testing process consisted of poking at the application and trying to break things. I would store up two or three issues before trying to run because this process was so painful. Of course, this took ages because I would find something wrong and would have to quit testing, fix the code and rerun. I had no idea how broad changes would be if I fixed a given component. The further down in the architecture, like a database helper class, the scarier this became. Even to test the particular UI bit that I knew that it affected, I would have to log into the app, navigate to the page with the error and then fill out the form and so on. Since I couldn’t possibly know everywhere that was affected this could take a lot of time and it still wouldn’t be right.

Somewhere in here, I would have flash backs to my mainframe days where you’d write code, hand walk it, submit the 10 new lines of code to the compiler and wait. You’d have the results of your compile printed out 2-4 hours later, depending on whether or not the big iron was under load. The next step was to correct the spelling because none of the tools had IntelliSense and start the whole process over again. Throw in a lunch and that was your whole day. You had accomplished the task of compiling 10 new lines of code. The next day, you’d get to test it and then fix it again.
These practices impede forward progress on a project so that I can either laugh or cry.  I stay sane by realizing first that I’m not, by any stretch of the imagination, telling war stories that you haven’t personally felt as well and second, there is a better way now. 

My current project is much different because of testing, testing and more testing. I know exactly what I have and haven’t broken a mere matter of seconds after making the change. Let’s start by talking about the database helper class scenario. I make a change to one of the methods in the database helper class. Now, rather than running and guessing as to what’s changed, fixed or broken, I’ve got automated tests that test that particular method in several different ways directly. I pass in several types of good data and bad data. If it stopped here, that would be good, but it still might have broken something else that I didn’t realize. In addition, I’ve got automated tests for the data classes that use the utility classes. And I’ve got automated tests for the middleware that uses those data classes. And I’ve got automated tests for the ASP.NET UI. And the best part is that all of the backend and middleware tests run in about thirty seconds. The ASP.NET code actually makes the HTTP calls and renders the HTML, parses it and so on so they take a touch longer. Even running all of the tests takes just a couple of minutes.

At that point, I can feel free to move on and write more code without that same knot in my stomach that I’ve broken something that I didn’t know about. I’m not spending time repeating myself and typing in the same meaningless test input into the UI over and over. I am using the computer to do that for me. It makes for more repeatable, consistent tests that actually get executed.
Now, that being said, I don’t believe that the tests that I’m writing can replace the testing that a business analyst, the user or a quality assurance team does. When the tests that I run pass, that means that the code does what I meant for it to do. There are a number of limitations with this. First, it could be that I forgot a possible scenario. Second, the code that does what I meant for it to do might not do what the user or business analyst meant for it to do. If we have communicated well, it will be close but it’s possible that there a misunderstanding which will have lead me down the wrong path.

I still haven’t bought into all of the TDD philosophy. I still don’t write my tests before I write the code. I just haven’t been able to get my head around that concept yet. I have trouble thinking about all of the ways that the code is going to be used and writing tests and then writing the code. I’m thinking that I will make that transition at some point for some tests.
I’ve been thinking that I should take my use cases and start from there writing tests. In future posts, I’ll talk about my thought process here.

One of the keys to a good unit testing experience is having the proper tools. I’ve put together what I think is a good toolset, at least for ASP.NET, that is able to test the vast majority of what I need to test. I'll talk about this toolset and how you can get started on unit testing yourself in future posts.



Monday, January 17, 2005 4:57:46 PM (GMT Standard Time, UTC+00:00)  #  Comments [0] 

# Monday, December 06, 2004
.NET To Go Mobility Roadshow in Grand Rapids - Followup

I want to thank everyone for coming out to the .NET To Go Mobility Roadshow in Grand Rapids. I had a great time and hope to come back to Grand Rapids more often.

We had about 40-45 participants and all seemed to enjoy themselves and were really engaging. If I had a typical Grand Rapids group – I’m definitely going to have to speak there more often. I was a little disappointed at the student attendance as we only had about half a dozen or so and getting students to attend was one of the reasons that we held it at the GVSUAuditorium (Nice facility).

Many thanks go to GVSU – for hosting the event, Eric Maino for organizing and running the event and West Michigan .NET Users Group and the Grand Valley State .NET Users Group for helping with marketing.

As promised – below is the link to the code samples that I wrote or showed during the show. The Scan and Amazon only works on a Symbol device with a barcode scanner and the Symbol .NET SMDK installed.



Monday, December 06, 2004 4:20:46 PM (GMT Standard Time, UTC+00:00)  #  Comments [0] 

# Saturday, November 20, 2004
Gabriel Torok on Channel 9

Gabriel Torok from Preemptive Solutions talks about the Dotfuscator on Channel 9.

Even though I use the Dotfuscator – I learned some things watching the demo.



Saturday, November 20, 2004 5:02:34 PM (GMT Standard Time, UTC+00:00)  #  Comments [0] 

# Tuesday, November 16, 2004
Grand Rapids is getting the .NET Mobility Roadshow on Dec. 2.

.NET To Go Mobility Roadshow on Thursday, December 2, 2004 at the DeVos Center-Loosemore Auditorium.

.NET To Go

The .NET To Go Mobility Roadshow will provide you with the answers to your mobile development questions. Digging into the details, using more code and fewer slides, these technical sessions will show you how to develop and implement mobile solutions using the .NET Compact Framework and languages you are already familiar with. To register for this FREE event or to learn more, go to www.msmobilitytour.com.

Registration is required to make sure that you can get in. You can register at the MS Events page.



Tuesday, November 16, 2004 6:38:17 PM (GMT Standard Time, UTC+00:00)  #  Comments [0] 

# Monday, November 15, 2004
Process Explorer

I just found the Process Explorer via Jonathon Hardwick. This is the TaskMan on steroids that we’ve needed for a while.

This is a very cool utility. There are a couple of features that I want to point out.

The most obvious one to me is that it allows me to drill down into processes and see what’s inside of a given process, like svchost – which I always seem to have 2 or more of running at any given time.

  Screenshot of the Process Explorer in action.

Second, as the picture above shows, it allows for highlighting of difference processes and the really great part is that it allows me to configure those highlights.

configuring the highlights

Third, it gives me locations on the disk of each of the exe/dlls that are running.

Fourth, it gives me whatever descriptive information that it can as far as company name, description of the exe and so on.

There are a lot more good features about it. However, I’m going to leave discovering them as an exercise to the user.



Monday, November 15, 2004 12:37:32 PM (GMT Standard Time, UTC+00:00)  #  Comments [0] 

# Thursday, November 11, 2004
Most creative CV I've ever seen.

Someone forwarded me this resume (CV depending on where you are in the world). I get a number of these, but this took some real creativity so I thought I'd post it here.

Here's the English version:
http://213.186.36.10/~al/alstudio/cv/en.htm

He did it in his native French as well:

http://213.186.36.10/~al/alstudio/cv/fr.htm

Here's the full list - including the standard word formatted CV.
http://213.186.36.10/~al/alstudio/cv/en.htm

Anyways - kudos for creativity and I hope that this helps him find a job.



Thursday, November 11, 2004 3:28:46 PM (GMT Standard Time, UTC+00:00)  #  Comments [0]