Unit testing code behinds in ASP.Net Web Forms

13 June, 2010 § 7 Comments

Have you ever inherited an ASP.Net website with waaaaaaay too much logic in the code behinds?

A while back I came up with a solution to solving this problem. I don’t have a name for it, but if you do, please leave a comment at the end of this post.

The problem that I was trying to solve is that I wanted to make a new page and implement it using Test Driven Development. The hard part was that there was a lot of code that basically dealt with the visual aspect and interaction of the page but not much with the data model. I needed to find a way to write tests around this code, as the data model code already had a framework for writing tests.

Here is an example of the before-case:

public class CodeBehind : System.Web.UI.Page {
   protected void btnFindUser_Click(Object obj,  EventArgs e) {
      if (Page.IsValid) {
         var dbConnection = new DatabaseConnection();
         var users = dbConnection.GetUsers( txtQuery.Text );
         if ( !users.empty() ) {
            dataTable.Bind(  users );
         }
      }
   }
}

What I came up with was an introduction of a "controller" class that lived outside of the ASP.Net Web Forms project. Here is an example of the after-case:

// CodeBehind.aspx.cs
public class CodeBehind : System.Web.UI.Page {
   protected void btnFindUser_Click(Object obj,  EventArgs e) {
      controller.FindUser( Page.IsValid, txtQuery.Text, dataTable );
   }
}

// CodeBehindController.cs
public class CodeBehindController {
   public void FindUser( bool pageIsValid, string query, DataTable dataTable ) {
      if ( pageIsValid ) {
         var dbConnection = new DatabaseConnection();
         var users = dbConnection.GetUsers( query );
         if ( !users.empty() ) {
            dataTable.Bind( users );
         }
      }
   }
}

// CodeBehindControllerTests.cs
public class CodeBehindControllerTests {
   public void FindUser_WithNoUsersFound_DataTableIsEmpty() {
      DataTable table = new DataTable();
      CodeBehindController controller = new CodeBehindController();

      controller.FindUser( true, "ImpossibleUserToFind", table );

      Assert.IsTrue( table.empty() );
   }
}

With that, I can now mock out the DatabaseConnection and the DataTable and I'm good to go. By passing in Page.IsValid instead of the whole Page object, I'm able to provide types that are easier to instantiate and I also now have code with less dependencies.

Getting this to work is actually very simple. Just introduce another class and put all of your logic in that class. There shouldn't be a single conditional in your *.aspx.cs page. As long as you follow this pattern, it should be pretty easy to TDD your next ASP.Net Web Forms page.

Any questions? Leave a comment and I'd be glad to help.

Code Jam programming competition

11 April, 2010 § 2 Comments

I found out about the Google Code Jam programming competition this past week through Reddit and registered for it. It’s my first programming competition so I’m pretty excited to see how it turns out.

I’ve started to go through the practice problems listed on the site and completing them as though they are part of the competition. As I compete them, I’ll upload my solutions to the problem. Since these solutions are written in haste and I don’t plan on making the code maintainable, for your own benefit please don’t copy the code and use it in an actual production scenario.

The first problem that I have solved is the Alien Numbers problem from April, 2008.

The decimal numeral system is composed of ten digits, which we represent as “0123456789″ (the digits in a system are written from lowest to highest). Imagine you have discovered an alien numeral system composed of some number of digits, which may or may not be the same as those used in decimal. For example, if the alien numeral system were represented as “oF8″, then the numbers one through ten would be (F, 8, Fo, FF, F8, 8o, 8F, 88, Foo, FoF). We would like to be able to work with numbers in arbitrary alien systems. More generally, we want to be able to convert an arbitrary number that’s written in one alien system into a second alien system.

See if you can solve this problem. Then continue reading to see my solution.
« Read the rest of this entry »

Section 7.7: Side-effects in functions

30 December, 2009 § 6 Comments

I’ve been reading Bertrand Meyer’s Object-Oriented Software Construction recently and have enjoyed learning a bit about the Eiffel programming language (also written by Meyer) at the same time.

The book focuses on principles of OOP (such as modularity and re-usability), techniques (such as generics), and also discussions such as genericity versus inheritance.

While there are many great topics covered in the book, I wanted to first write a blog post about ยง 7.7: Side-effects in functions.

Side-effects in functions

C#, much like Eiffel, has the notion of properties and functions. Both of these can be used the exact same way. For example, a Point class may have a property Theta or a function Theta:

// C#
public class PointP {
   public double Theta { get { return 0.0; } }
   public double Rho { get { return 0.0; } }
}

public class PointF {
   public double Theta() { return 0.0; }
   public double Rho() { return 0.0; }
}

public class Test {
   public static void Main() {
      var ppoint = new PointP();
      var fpoint = new PointF();
      Debug.Assert( ppoint.Theta == fpoint.Theta() );
   }
}

While both can accomplish the same goal, there are semantic differences between the two. Meyer's espouses that properties should be thought of as simple accessors, while functions may be thought of as mutators. Within Eiffel, this is referred to as the Command-Query Separation.

Therefore, functions like C's getint() violate this principle, since they return the last integer seen on the input stream and advance the cursor at the same time. getint() is therefore an accessor and a mutator.

Accessors should have the property that they can be called multiple times with the same output each time.

Functions, in their most mathematical sense, should have the property that they can be called multiple times given the same input and have the same output each time.

In this example, Meyer would have written something like this:

/* C */
FILE input;
input.advance();
int lastSeenInteger = input.lastint;
ASSERT( 2 * input.lastint == input.lastint + input.lastint );

The same cannot be said for getint().

While we have now achieved an arguably better solution than what existed before, Meyer leaves the reader to decide if the function should mutate itself or return a mutated object. I will take this opportunity to conclude on his discussion.

Taking away the guesswork

At this point, it is up to the programmer to know if the function is going to mutate itself or return the mutated object. The programmer may check the interface of the class explicitly, or use features of their IDE to tell them if this function returns a void or a separate FILE reference.

By convention, Ruby solves this problem by using an exclamation point at the end of the function name to be explicit that the function will change the internal state of the object.

# Ruby
input_b = input_a.advance
b_last_int = input_b.lastint
input_a.advance!
a_last_int = input_a.lastint
assert( a_last_int == b_last_int )

Conventions like these remove guesswork out of the equation and allow the developer to know when they are calling a function with side-effects.

Readability is key

In the end, we as software developers should strive for the most readable and maintainable code. Each one of these tools, like side-effect function conventions in Ruby, should allow us to achieve this goal.

Do you have any conventions that you use or know of that call out side-effects in functions?

Bad Programming Examples in C#

23 February, 2009 § Leave a comment

I’m starting to compile a list of constructs I’ve seen in production C# code that needs to be modified. Code Analysis will flag most of these. Here is the first of them, with more to be added later:

1. Never leave a blank catch statement or use catch(Exception)

In C#, if you write catch(Exception) or a blank catch, the exception will be casted to a System.Object. This will also catch non-CLS compliant exceptions. If you can’t do anything to remedy the exceptional situation, you shouldn’t be catching the exception. Usually when you see a code construct like this, the exception is rethrown. Not only is this unnecessary and bad programming, it ruins the stack trace and any other important information that Windows Error Reporting can provide for you.

If you are unsure what type of exception can be thrown, you should check the documentation. If you are catching the exception so that you can perform some cleanup before exiting, then you should move that cleanup code to a finally block. If the latter is the case, then you probably don’t need the catch block there in the first place.

If you run Code Analysis on your code, you will receive a CatchNonClsCompliantExceptionsInGeneralHandlers warning.

More information can be found about why not to have empty catches in your code at the CLR Team Blog.

Stepping in to .Net source code with VS2008 SP1

31 January, 2009 § Leave a comment

With the release of Visual Studio 2008 SP1, a new feature was introduced and touted, but not turned on by default. This feature allows you to step in the .Net source code while debugging in Visual Studio. If at any point within your code, you can look at the callstack and traverse all the way down to the creation of the current running thread. Very cool!

To do this, you just have to change a couple default options.

First, go to Tools -> Options. Choose “Debugging” from the left-hand side menu, and uncheck the Just-my-code option. Next you’ll want to check “Enable .Net framework source stepping”.

Hit OK, and the symbols should* start to download from Microsoft’s servers, complete with developer comments.

The first time view the code you will be prompted to accept their license agreement.

*If the symbols didn’t download when you hit OK, you can go to the Symbols submenu and choose to download the symbols explicitly from the Microsoft servers. I’ve noticed this happening on a coworker’s machine once already.

Where Am I?

You are currently browsing entries tagged with c-sharp at JAWS.

Follow

Get every new post delivered to your Inbox.

Join 982 other followers