TwitterFacebookGoogle

Writing integration tests for ASP .NET with Selenium 2.0 – Part 1

This is the first in a series of posts on writing integration tests for ASP .NET using the Selenium 2.0 web application testing system.

UPDATE: This post was updated on April 15, 2012 to explain how to setup and configure Selenium 2.0.

In this post, I explain what Selenium is, why use it and how to setup and configure it. In the next subsequent posts, I’ll do a code walk-thru and also share some advanced scenarios.

What is Selenium?
The best description of Selenium is probably the one mentioned on their website:

“Selenium automates browsers. That’s it. What you do with that power is entirely up to you. Primarily it is for automating web applications for testing purposes, but is certainly not limited to just that. Boring web-based administration tasks can (and should!) also be automated as well.”

Why use Selenium?
There are other integration testing web frameworks out there such as WaitN or the Lightweight Test Automation Framework for testing ASP .NET web apps. So, why use Selenium? Here are the main reasons why picked it:

  1. Selenium allows you to record test scenarios manually (by browsing to specific pages and clicking buttons, etc.) as well as programmatically (by coding up a test case). Thus the tool can be used by both developers and QA’s. You can even use a combination of recorded test scenarios and C# test cases to integration test your application.
  2. One feature that I really liked is that you can export a recorded test scenario as a C# test-case! This technique can be used to drastically speed up the Selenium learning curve since it spits out code that you can use inside C# test-case. For instance, when you’re unsure how to code up a specific scenario you can manually record it and then export it to see what the code needs to look like.
  3. The recorded scripts can be used as a tool to speed up manual testing. For example, I never manually login into the web application that I am currently implementing anymore. Instead I run a test scenario that I had previously recorded, conveniently named Login, that logs me in. No more manually typing in username/password! You can use this technique to directly land on specific pages and/or fill-in and submit forms as well. This adds up to save you boat loads of time during your manual testing.
  4. Finally, the test recorder is a small Firefox plugin and integrates real nice with Firefox.

Convinced? Awesome! Let’s move on to setting up Selenium…

Initial Setup
There are two parts to setting up Selenium:

  1. Installing the Selenium IDE: A Firefox plugin that allows you to manually record test scenarios. Find and download the Selenium IDE plugin from the Selenium Downloads section. After it downloads, fire up the Firefox browser -> Go to Add Ons from the Main Menu -> Click the Settings icon -> Select the Install Add-On From File option -> Click Install Add-On.
  2. Installing the Selenium 2.0 WebDriver for .NET: Accepts commands from your C# test cases and automates the browser. Using the NuGet Package Manager Console, run the below commands to install the Selenium packages. Make sure you select your test project as the “Default project” inside the Package Manager Console before running the commands. This way the DLLs will get added to the correct project.

    Install-Package Selenium.WebDriver
    Install-Package Selenium.Support

    Okay, at this point, we should be all set with Selenium. Verify the following:

    - You are able to record a test scenario: Fire up Firefox. On the Main Menu, under Web Developer, you should now see a Selenium IDE option. Or you can use the Ctrl+Alt+S shortcut key to bring it up. Click the record button on the top right, browse to goggle.com, and search for something. Click the record button again to stop the recording. Now try running the script by clicking the play button and see what happens. Make sure you are already on the google.com page when you click the Play button. Hopefully, it worked. If not, call me. I’ll help you out and I only charge a $150/hr. Just kidding. If it doesn’t work then try re-installing the plugin, I guess. :)

    - You are able to write and run C# integration test-cases using Selenium – This is what I go over in my next post on Selenium.

    Twitter Email Linkedin Digg Stumbleupon Subscribe

To TDD or Not To TDD?

Recently, I was involved in a discussion with a colleague of mine that was focused around TDD – Test-Driven Development.

During the discussion he mentioned that he personally finds the process of coding up the method first and test later to be easier, natural and more efficient. Writing the test-first just seems more difficult to do and less efficient. He then went on to state his reasons:

He said, and I agree with him here, it’s probably easier and feels natural because that’s the way he has always programmed. Create functionality and then test that functionality. TDD flips that around and as result you have to “re-learn” development. Something he wouldn’t mind doing, expect that…

In his opinion, TDD is a slower way to code. Here is his reasoning: A great majority of the time, you’re going to change the code that you wrote to begin with – you will rename the class or method, move things around, change the number of parameters or throw away the first attempt and start again. If you were to write the tests first then those tests would have to change as well! As a result, you’re increasing the amount of effort involved. It’s much faster to just write the test after the code has been finalized.

Until a year ago, those were my thoughts exactly. Then one day (well, probably more like over a period of several months, several books and several articles) I finally found the missing piece to the puzzle. The piece that made TDD possible for me without causing me spend countless hours making significant changes to my test cases because I would keep making significant changes to my code-base. I realized what TDD actually states. Which is: Do NOT write a single piece of production-code before first writing a test for it. And there it is, the missing piece to the puzzle – production-code!

Ah ha, I said! I finally get it! In other words, if you’re unsure how about the solution is going to look like or work – write non-production code first to work out ideas, fill-in the gaps in requirements, get your questions answered, and get a feel for what the overall solution will look like. Then and only then are you ready to write production-code!

Here is the process I now follow during the development:

1. Write a spike or POC code to “brainstorm” what the solution might look like. Sometimes I spend quite a bit of time here. Since in the brainstorming process you’ll find out gaps in requirments or will have to go research the third-party product that you’re planning use.
2. Once you’ve got a good grip on what the overall solution might look like and how it’s going to work, I throw away the spike (or at least put it out of sight).
3. I then write a failing test case.
4. Write code to make it pass.
5. Back to Step 1 if I am unclear on what the next piece of functionality entails; otherwise, Back to Step 3.

So I mentioned that to him and he sort of agreed but not really. He was sort of on the fence. After further discussion we hit upon another point on why to follow TDD that really hit home for him. Here is the example I gave him:

Consider the following: You’ve got X number of test cases in place for a piece of existing functionality. All of the tests pass and everything is working just fine. Then you get a change request. You make the change and then run all the tests. They all pass. Are you done? It’s a little difficult to say, isn’t it? Somewhat open to interpretation. I’ve come across developers who think that they are done at this point because they didn’t break any existing tests. But they forgot to ask – have I added a test for the new change that I made?

On the other hand, if we were to first write a failing test for the change request then there would be no debate on whether or not a test is needed. This where TDD really shines and ensures that we’ve got tests for all of the functionality. When pressure creeps in, and this is especially true for change requests, then the discipline to add tests after the fact even when all of the existing tests are passing becomes very hard to follow-through on.

Sorry for the long-winded ranting. Hopefully you got something out of it. :)

Twitter Email Linkedin Digg Stumbleupon Subscribe

Refactoring Code to enable Unit Testing

Imagine the following (which you’ve very likely run into in the past):

You join a new company and inherit a humongous existing code base. You are told to add some new functionalities without of course breaking existing functionality. “No problem”, you say! “I’ve done this before.”

You’ve got clear requirements and complete access to the existing code base. After some investigation, you figure out that you need to add a few methods to an existing class. One of these methods is:

CustomerService.CanPurchaseProduct(int productId)

The existing CustomerService class looks somewhat like the following:

public class CustomerService
{
   public CustomerService(int customerId)
   {
      custManager = new CustomerManager();
      cust = custManager.GetCustomer(customerId);
   }
 
   ...other methods...
 
   private CustomerManager custManager;
   private Customer cust;
}

You will also be utilizing an existing class named ProductService. Below is a bare-bones outline of this class:

public class ProductService
{
   public ProductService(int productId)
   {
      prodManager = new ProductManager();
      prod = prodManager.GetProduct(productId)
   }
 
   ... other methods below .....
 
   private ProductManager prodManager;
   private Product prod;
}

Your requirements state the following:

– Product must be in stock
– Customer must be a member IF product is for members only

Being the good developer that you are, you start, of course, by writing the unit tests. They look something like the following:

[TestCase]
public void CanPurchaseProduct_InStockAndForAll()
{
      int customerId = 123;
      int prodId = 1;
 
      //TODO: Mock this scenario
      CustomerService svc = new CustomerService(customerId); 
     Assert.IsTrue(svc.CanPurchaseProduct(1));
}
 
[TestCase]
public void CanPurchaseProduct_NotInStock()
{
      int customerId = 123;
      int prodId = 1;
 
      //TODO: Mock this scenario
      CustomerService svc = new CustomerService(customerId); 
     Assert.IsFalse(svc.CanPurchaseProduct(1));
}
 
[TestCase]
public CanPurchaseProduct_NotAMember()
{
      int customerId = 123;
      int prodId = 1;
 
       //TODO: Mock this scenario
      CustomerService svc = new CustomerService(customerId); 
     Assert.IsFalse(svc.CanPurchaseProduct(1));
}

Your initial implementation of the CanPurchaseProduct() method looks like the following:

public class CustomerService 
{
    public bool CanPurchaseProduct(int productId)
    {
       ProductService prodService = new ProductService(productId);
       if(!prodService.IsInStock())
         return false;
 
       if(prodService.IsMembersOnly() && !custService.IsMember())
         return false;
 
      return true;
    }
}

If you’re familiar with unit tests, you’ll recognize an issue right away: The way the implementation currently stands, it is impossible to mock out the different scenarios that we have coded for in our test cases. The reason for this is tight coupling and lack of abstraction. The CustomerManager, ProductService and ProductManager classes are being directly instantiated by the classes that use them – an example of tight coupling. Furthermore, the classes do not implement an interface thus making it impossible to substitute mock versions for them – a direct result of lack of abstraction. So how do we fix this with minimal changes to the existing classes? Below is one strategy:

1. Account for dependencies

The first step is figure out the dependencies. A dependency is any class, resource file, configuration file, etc. that your code is using either directly or indirectly. In our case, we have the following dependencies:

- CustomerManager
- ProductService
- ProductManager (used by ProductService).

2. Make the dependencies “plug-and-play”

Now that we know what the dependencies are and the places where they exist, our next step is to remove all the “knots” so that we can make them plug and play. By “knots”, I refer to statements like the following:

   - custManager = new CustomerManager()
   - productService = new ProductService()  
   - prodManager = new ProductManager()

Instead of the classes directly instantiating dependencies, the idea is to provide it to them. This technique is know as Dependency Injection. There are multiple ways of doing this. Keeping in mind that we need make a minimum number of changes to the existing code base, we’ll go with the simplest one:

Modify the constructors/methods to take in the dependencies as parameters.

This is illustrated below:

public class CustomerService
{
   //Instead of directly instantiating, we pass in the dependency.
   //All new classes can now start using this one to allow for unit      
   //testing.
   public CustomerService(int customerId,  
     CustomerManager custManager)
   {
      cust = custManager.GetCustomer(customerId);
   }
 
   //Original constructor becomes empty.  
   //We still need to keep it around since it is probably used other
   //existing classes
   public CustomerService(int customerId) : 
       this(customerId, new CustomerManager())
   { }
 
   ...
 
   //Note that the method is now taking ProductService as a parameter
   //instead of directly instantiating it.
   public bool CanPurchaseProduct(int prodId, 
        ProductService prodService)
   {...}
}
 
public class ProductService
{
   //Instead of directly instantiating, we pass in the dependency.
   //All new classes can now start using this one to allow for unit      
   //testing.
   public ProductService(int productId, ProductManager prodManager)
   {
 
   }
 
   public ProductService(int productId) : 
     this(productId, new ProductManager()) {}
}

Note: When it comes time to re-factor/re-design/re-architect (whatever you want to you call) your entire application, you should go with a better alternative to handle dependency injection instead of the approach shown here. I would recommend using a tool such as Spring .NET.

3. Abstract them away!

The final step then is create an interface for each of the concrete classes and replace all references to the concrete classes with their associated interfaces.

public interface ICustomerService
{
  bool CanPurchaseProduct(int customerId, IProductService  
    prodService);
}
 
public interface ICustomerManager {...}
 
public interface IProductService {...}
 
public interface IProductManager {...}
 
public class CustomerService : ICustomerService 
{
  public CustomerService(int customerId, ICustomerManager)
  {...}
 
  public bool CanPurchaseProduct(int prodId, IProductService 
    prodService) 
  {...}
}
 
public class CustomerManager : ICustomerManager {...}
 
public class ProductService : IProductService 
{
  public ProductService(int prodId, IProductManager) 
  {...}
}
 
public class ProductManager : IProductManager {...}

Now, we can finally substitute our mocks for the dependencies in our unit tests as shown below. Note that in the test cases below I am using the Moq Unit Testing Framework to setup the mocks but you could use any other framework that you’d like or none at all (if you wish to create the mocks manually).

[TestCase]
public void CanPurchaseProduct_InStockAndForAll()
{
   int customerId = 123;
   int prodId = 1;
 
   //create mocks
   Mock<ICustomerManager> custManager = 
     mockFactory.Create<ICustomerManager>();
 
   Mock<IProductService> prodService = 
      mockFactory.Create<IProductService>();
 
   Customer cust = new Customer(123);
   cust.IsMember = false;
 
   //setup mocks
   custManager.Setup(cm => cm.GetCustomer(123)).Returns(cust);
 
   prodService.Setup(ps => ps.IsInStock()).Returns(true);
   prodService.Setup(ps => ps.IsMembersOnly()).Returns(false);
 
   //run test
   CustomerService svc = new CustomerService(customerId, custManager.Object); 
   Assert.IsTrue(svc.CanPurchaseProduct(1, prodService.Object));
}
 
[TestCase]
public void CanPurchaseProduct_NotInStock()
{
   int customerId = 123;
   int prodId = 1;
 
   //create mocks
   Mock<ICustomerManager> custManager = 
      mockFactory.Create<ICustomerManager>();
 
   Mock<IProductService> prodService = 
      mockFactory.Create<IProductService>();
 
   Customer cust = new Customer(123);
   cust.IsMember = false;
 
   //setup mocks
   custManager.Setup(cm => cm.GetCustomer(123)).Returns(cust);
   prodService.Setup(ps => ps.IsInStock()).Returns(false);
 
   //run test
   CustomerService svc = new CustomerService(customerId, custManager.Object); 
   Assert.IsFalse(svc.CanPurchaseProduct(1, prodService.Object));
}
 
[TestCase]
public CanPurchaseProduct_NotAMember()
{
   int customerId = 123;
   int prodId = 1;
 
   //create mocks
   Mock<ICustomerManager> custManager = 
      mockFactory.Create<ICustomerManager>();
 
   Mock<IProductService> prodService = 
      mockFactory.Create<IProductService>();
 
   Customer cust = new Customer(123);
   cust.IsMember = false;
 
   //setup mocks
   custManager.Setup(cm => cm.GetCustomer(123)).Returns(cust);
 
   prodService.Setup(ps => ps.IsInStock()).Returns(true);
   prodService.Setup(ps => ps.IsMembersOnly()).Returns(true);
 
   //run test
   CustomerService svc = new CustomerService(customerId, custManager.Object); 
   Assert.IsFalse(svc.CanPurchaseProduct(1, prodService.Object));
}

And there you have it. We were able to take an existing code base that had no support for unit-testing and re-factor it so that the additional methods that we added could be unit-tested. Furthermore, we did this without requiring us to make any sweeping architectural changes to the existing code base.

One could argue if the additional work is really worthwhile. If you’re already a test-driven developer then I don’t need convince you that it is definitely worthwhile. But if you’re not then I’ll highlight a few long-term benefits that result from the additional work:

- The code base is now more extensible. It can work with other implementations for ICustomerManager and IProductService.
- At any given time one can run the test cases and know if anything has been broken.
- Unit-testing forces us to think about the dependencies and code in a manner that leads to clean and easy-to-understand code.
- The test cases serve as an up-to-date documentation on what the code does and how it is being used.

I hope that the above points will encourage you to investigate the pros/cons of test driven development more fully.

Twitter Email Linkedin Digg Stumbleupon Subscribe

Fix to Mock.SetupAllProperties() – Not working in Moq 3.0

If you download the latest version of Moq, you’ll notice that the Mock.SetupAllProperties() method does not work. Try it in Debug mode and you’ll notice that the method just gets skipped.

Upon inspection, I discovered that a conditional attribute that was being applied to the method which was causing it to be skipped. I am assuming that attribute was meant to be removed but got overlooked.

Anyways, to fix it, here is what you do:

1. Download the source code for Moq and open up the file Mock.Generic.cs
2. Find the method SetupAllProperties() and remove the conditional attribute:
[Conditional("DESKTOP")]
3. Re-build and overwrite for existing Moq.dll that your project is referencing with the new one.

Cheers!

Twitter Email Linkedin Digg Stumbleupon Subscribe

Integrating TypeMock with ASP .NET Unit tests

When it comes to writing unit tests for your ASP .NET pages, there isn’t much help out there. I experimented with a few open source testing tools and found some major limitations.

Both NUnitAsp and WaitN, for instance, are “client-side” tools. In other words, you have to write your tests against the actual HTML output. For example, to get the value of a textbox, you have to specify the actual HTML id of the textbox. That’s painful! Especially, since ASP .NET ends up assigning long and complicated ID’s to your controls. Plus NUnitAsp is no longer being maintained or supported.

Unlike NUnitAsp and WaitN, VS Studio ASP .NET Unit testing let’s you examine the actual HttpRequest object. What this means is that you can call methods on your Page and get access to the controls within the page. VS Studio ASP .NET is a pretty decent tool and maybe the answer for you. IF you don’t need to use TypeMock that is. But if you do, then tough luck because VS Studio ASP .NET unit tests don’t work with TypeMock. If you give it try, you’ll get the following exception:

Test method AzAsh.WebApp.Tests.DefaultTest.LoginNotRequiredTest threw exception:  TypeMock.TypeMockException: 
*** Typemock Isolator is not currently enabled. 
To enable do one of the following:

* To run Typemock Isolator as part of an automated process you can:
   - run tests via TMockRunner.exe command line tool
   - use 'TypeMockStart' tasks for MSBuild or NAnt

* To work with Typemock Isolator inside Visual Studio.NET:
        set Tools->Enable Typemock Isolator from within Visual Studio

For more information consult the documentation (see 'Running' topic).

Check the enable property as they have suggested and you’ll notice that Typemock is enabled! So, what gives? I have no idea. But I do know that Ivonna – a ASP .NET testing tool that is being developed in partnership with TypeMock WILL let you work in conjunction with TypeMock. Like VS Studio, it allows you to examine the intrinsic objects, such as the Page object. In addition, it’s got another neat feature that let’s you inject setup code and assertions into your page’s lifecycle event handlers – very handy especially during type mocking. The only drawback is that it’s a little slow. The unit tests take a while to run.

So if you’ve been scratching your head trying to figure how to develop ASP .NET tests that can work with TypeMock, Ivonna is probably the tool you’ve been waiting for!

Twitter Email Linkedin Digg Stumbleupon Subscribe
CyberChimps