ASP.NET MVC / Ajax Example

August 1, 2011

Let’s assume you have a page which has a small section that should update its content based on a tab clicked by the user, just like the image below.

web page with tabbed section

We could solve it the traditional way, but re-rendering the entire page each time a tab is clicked. Or better yet, we could use Ajax to only re-render that section.

This is how you could accomplish that if you’re using ASP.NET MVC.

Create a new Controller/Action

For simplicity’s sake, let’s assume we already have the code for the main page. All we need to do now is build the logic for the Ajax section. In that case, the first thing we’ll need is a controller/action to handle our Ajax requests. Here’s an example:

 

public class MyController : Controller
{
	// Other code

	[HttpGet]
	public PartialViewResult TabSection(int tabId)
	{
		var model = buildViewModel(tabId) // logic to build viewModel based on tabId
		return PartialView("_TabSection", model);
	}
}

As you can see, our action will just be expecting an http get request with a tabId param. Notice the PartialViewResult return type as opposed to the more common ViewResult. This is because we don’t want to render a full View (with optional master page and complete html markup); instead, we want a partial view (i.e., a sub-section of an entire html page).

Create a partial to render your Ajax section

This is the partial that will render the viewModel returned by our MyController.TabSection() action. As you can see in our action implementation, we decided to call it _TabSection.cshtml (assuming you’re using razor). I won’t show the code to implement this partial here, since there’s nothing special about it – it is just like any other ASP.NET MVC partial in your project. In fact, there’s nothing that stops you from using this partial in any other (non-Ajax) operation in your website, as long as you pass the correct ViewModel type to it.

Wire up the code in your main View

This is the last step to hook up your Ajax control. Using jquery, we can take advantage of its jQuery.get(). We’ll end up with something like this:

 

<!-- meta data -->
<script type="text/javascript">
	$(function(){
		$("#tabs a").click(function(){
			var tabId = $(this).attr("tabId");
			var ajaxUrl = "/MyController/TabSection?tabId=" + tabId;
			$.get(ajaxUrl, "",
				function(data){
					$("#tab_content").html(data);
				}, "html");
		});
	});
</script>
<!-- left nav bar html -->
<div id="tabs">
	<a href="javascript:void(0)" tabid="1">One</a>
	<a href="javascript:void(0)" tabid="2">Two</a>
	<a href="javascript:void(0)" tabid="3">Three</a>
</div>
<div id="tab_content">
	<!-- Tab content: to be updated by the Ajax call -->
</div>
<!-- image and other stuff's html -->

Notice the tabId attribute in the tab’s anchor tags. This is not a valid html attribute, but we can use this as a trick to have our jquery code figure out the clicked tab when generating our Ajax request. The jquery.get() abstracts all the logic to generate the Ajax call and process its response. In this example, once the response is received, it updates the html within the tab_content div.

As you may have realized, besides the jquery magic, the beauty is that the tab html content is returned by the MVC framework. In other words, by us just setting a controller action that calls a partial view (which is practically the same process we’d follow to create a new page in our MVC project), we are able to implement an Ajax control in ASP.NET MVC.

Using ASP.NET MVC’s Html.RenderAction()

July 27, 2011

Let’s say that you have a website that has certain “UI snippets” that will be reused across multiple pages. A site layout page could help you with this, but let’s say that (a) you won’t need to reuse these sections across all pages and/or (b) these snippets will be rendered in different parts of the markup, depending on the page.

One way to solve that problem is to create a partial and call it specifically from each page where you want it to be rendered. However, let’s say that the partial needs some business data (from the controller). Now the partial-only solution is not that practical.

An alternative would be to add it to the view model object you’re sending back from the page’s controller action and pass it on to the partial. But this means you’ll have to add it to each controller action providing the view model for each page in which you want to add the snippet. So you can see why this is not very DRY. You need a better solution.

Enter Html.RenderAction()

What RenderAction() allows you to do is to call a separate controller action/View from your original View. With this approach you can move the snippet’s business logic to a separate controller/action (which can be unit/integration tested on its own), and create its own View to render the snippet’s content. Then, all you need to do is to call Html.RenderAction() from the page in which you want to inject the snippet.

For example, let’s suppose that we want a little snippet in our website that shows up a summary of the current logged-in user (Name, gender, last time logged in, etc.) If we wanted to use the Html.RenderAction() approach to solve handle this situation, first you’d want to create a controller/action. For example:

public class UserController : Controller
{
	[ChildActionOnly]
	public ViewResult SummarySnippet()
	{
		var model = getUserSummaryInfo(); // builds ViewModel object
		return View(model);
	}
}

(*Note the ChildActionOnly attribute – it tells MVC that this action can only be called when injected from another page. I.e., it cannot be accessed directly by browsing to it).

This action uses the default view (SummarySnippet.cshtml if you’re using razor), in which you will have the markup for the snippet (not shown here). At this point, you’re pretty much ready to use this snippet in any page you want. All you’ll need to do is call Html.RenderAction in your appropriate page’s markup. For example:

@{Html.RenderAction("SummarySnippet", "User");}

The importance of not overloading your employees

May 13, 2011

There’s a common misconception in traditional-minded companies that your employees should always have something to do. That’s a very dangerous belief. Why… you may think (especially if you’re the one paying the staff or managing them).

Let me backtrack first. I know my statement is a very general one. I’m making that statement under the assumption that your work environment is characterized by professional, smart, creative, resourceful workers. Now under that assumption, I believe workers need some "free" time to strive. If you don’t believe me, look at companies like Google. I’m sure you’ve heard of their 20% time project rule. What that means is that they let their employees work on their own projects 1 full day out of a work week. That’s a pretty impressive number. And if you think that’s just a waste of time, consider that gmail, google talk and google news were among those projects in their infancy.

Now at this point, you may be thinking "well… they have the money to afford it." True, but the reality is that they didn’t get there just by chance. It is precisely this trust-based and progressive mentality that made them the successful players they now are. What I’m saying is, if you can’t afford letting them work on their own projects for 20% of their time, start with a lower percentage. Even if it’s just 10 or 5% of their time, that’s better than nothing. What you really can’t afford is to have a workforce that’s so overwhelmed by their workload that they become stagnant. Almost like machines or robots in an assembly line, unable to do anything else outside of a box.

The reality is that our brains need a mental break throughout the day. It is under those "calm" times your workers will think about extraordinary things. It is in those times when they will be able to think outside of the box, and consider new processes / solutions / alternatives that had not been considered before. Have you ever been thinking about how to solve a complex problem in your life for days, and then all of a sudden, when you’re taking a shower, driving, or at the most random moment you think of an alternative that had never crossed your mind? I’m sure you have. It is precisely the combination of thinking/not-thinking about a particular problem what eventually allows you to come to (at the best) a brilliant solution.

In short, if you’re a technology company (or for that fact any other kind of "progressive" company), you must make sure there’s room in your operations to allow your workers to develop new ideas. You must create a culture that supports and encourages such times.

Modeling a discrete property in a Rails entity

December 26, 2010

Let’s assume we have a rails app that has a model entity needing a discrete property. As an example, let’s pretend it’s a Person needing a gender. In C# or Java we could accomplish this by using an Enumeration. Unfortunately,  in Ruby there’s not a built-in enumeration type. There are ways to work around this. This post explains one way to accomplish this in Rails 3 (some adjustments may be needed for Rails <= 2).

The Person Class

So far, all we have is an empty Person class as generated by Rails scaffolding.

class Person < ActiveRecord::Base

end

What we’ll need to do is add a gender property to it.

Some solutions I ran into online solve this situation by persisting a String, which in this case would define the gender value (“Male” or “Female”). I don’t like that approach for 2 reasons: first it is using a String to represent a discrete value that should only have 2 statuses, and second it will require more resources to persist these data unnecessarily. And that’s just the beginning – think about internationalization just to give you more arguments against it.

Other solutions call for adding a totally new entity (Gender) in our rails model and creating a foreign relationship to it. Once again, this wastes unnecessary resources (why do we need a new Gender DB table just to hold two constant values? Moreover, Gender is not really an entity in our domain model.) Not a good solution, IMHO.

In short, what we’re aiming for is an int that represents our gender that we can easily persist. We’ll also take care of showing the right string in the Views.

Adding the Gender Constants and The Appropriate Validation

If you’ve already added a gender property (as an int) to your Person entity via scaffolding, the first thing we’ll do is define our Gender constants. We’ll define them as Hashes in order to also store their corresponding display name (you’ll see why when we adjust the Views). We’ll also add the validation of the gender property. Here’s what our Person class looks like now:

class Person < ActiveRecord::Base   
  MALE = { :value => 0, :display_name => "Male" }
  FEMALE = { :value => 1, :display_name => "Female" }

  validates_inclusion_of :gender, :in => [MALE[:value], FEMALE[:value]]
end

The validates_inclusion_of definition in our class will make sure that only 0 or 1 are assigned/persisted to/with our Person instances. The next step is to adjust our Views to use our new convention.

Fixing our Views

Let’s go ahead and add a couple of methods in our Person class to help us with the displaying of gender in our Views. The first one is a class method that will give us the list of options to be displayed when we want to render a dropdown list for our new property. Add this method to your Person class:

def self.get_genders_dropdown
    options = {
      MALE[:display_name] => MALE[:value],
      FEMALE[:display_name] => FEMALE[:value]
    }
end

The second method will provide us with the corresponding gender string for the Person instance we’re handling at any point in time. Here it is:

def gender_displayname
    return gender == MALE[:value] ?
      MALE[:display_name] :
      FEMALE[:display_name]
end

Now that we’re armed with these “helper” methods (which we can actually unit test), let’s adjust our views. First, in the _form.html.erb file generated by scaffolding, find the line for our gender input field and replace it with this:

<%= f.select(:gender, Person.get_genders_dropdown) %>

Note: This will generate a dropdown. You could use radio buttons instead, which would be better in this case. I’ll leave that to you as an exercise.

The last step is to go ahead and display the right string for the instance gender on the Views where the user is shown info about the Person gender. In particular, look for index.html.erb and show.html.erb and use this code line to replace “person.gender”:

<%= person.gender_displayname %>

That’s it. This will give us the ability to store gender as 0 or 1 in our DB and display it as Male or Female (correspondingly) for our Person entity.

Refactoring: Going the extra mile

You may have noticed that our Person class is a little “unclean.” Besides, what if we have another entity in our domain model (e.g., Animal) that also has a gender. We don’t want to have to retype all that for our second (third, fourth…nth) entity. In this Stackoverflow post, Jaime Bellmyer explains a neat way to do this using Rails’ plugin paradigm. Here’s a summary of the steps:

1) Extracting the common code out of our Person class: Basically add a new module in your rails’ project lib folder that will contain the common code (I called the file acts_as_gendered.rb):

module ActsAsGendered
  MALE = { :value => 0, :display_name => "Male" }
  FEMALE = { :value => 1, :display_name => "Female" }
  
  def self.included(base)
    base.extend(ActsAsGenderedMethods)
  end
  
  module ActsAsGenderedMethods
    def acts_as_gendered
      extend ClassMethods
      include InstanceMethods
      
      validates_inclusion_of :gender, :in => [MALE[:value], FEMALE[:value]]
    end
  end
  
  module ClassMethods
    def get_genders_dropdown
      options = { 
        MALE[:display_name] => MALE[:value],
        FEMALE[:display_name] => FEMALE[:value]
      }
    end
  end
  
  module InstanceMethods
    def gender_displayname
      return gender == MALE[:value] ?
        MALE[:display_name] :
        FEMALE[:display_name]
    end
  end
end

As you can tell some of the code applies to the class, whereas others to an instance of it; hence the need to extend/include the ClassMethods/InstanceMethods inner modules. The self.included method will just take care of the wiring when this module is mixed-in.

2) The next step is to automatically mix-in this new module on all our ActiveRecord::Base classes. This will save us some manual work when we want to add gender to an entity. To do this, add a new file under config/initializers (I called it gender.rb) with this code:

require 'acts_as_gendered'

ActiveRecord::Base.send(:include, ActsAsGendered)

Note: This is only called during the environment initialization, so if you already have a server instance running, you’d need to restart it before being able to use it (i.e., a simple update of an entity and reload of its views in rails won’t suffice).

3) The last step is to actually enable this new code in the appropriate entities. In our example, simple refactor your Person class to have this code:

class Person < ActiveRecord::Base
  acts_as_gendered
end

As you can see the acts_as_gendered() method is the only thing we need now to add gender to our entities. Don’t forget to use the get_genders_dropdown() and the gender_displayname() methods in the appropriate views and you are set.

Unit-Testing BlackBerry Applications

December 14, 2010

I’ve been trying to find an easy way to unit test BlackBerry (BB) applications for a while. It is a little challenging for different reasons (e.g., several network resource dependencies.) Nonetheless, there’s some hope, as described in this post. If you design your app with SOLID principles, your core areas will become easier to unit test.

There are a few frameworks that can help you unit-test your BB app; one of them is BUnit. This post describes how to use this framework to unit-test a simple BB Hello World app. Hopefully this will make it easier for some people to add automated tests to their BB apps.

Assumptions

You should have Java, Eclipse, and BB’s 4.5.0 JDK plugin already installed on your development environment (although it should work with different versions). You should also be familiar with basic BB development concepts.

Design

This is a simple HelloWorld app (nothing too fancy here). Below is its sequence diagram. Our unit test will be focusing on the HelloWorldRepository class. If you want to look at the final code source (including the unit test), you can download the source at git://github.com/iterativo/Blackberry-Hello-World.git

HelloWorldSequenceDiagram

Adding BUnit to your project

At this point, I’m assuming you’ve already created a BB project in Eclipse. After that, the first thing you’ll need to do is download BUnit (if you haven’t yet), unzip it and just copy the contents in src/jmunit into a new package folder in your BB project called test. This is what your project structure should look like so far:

ProjectStructure_1

Test-driving the Implementation

Let’s also assume that you’ve already implemented the HelloWorld and HelloWorldScreen classes in the sequence diagram. The HelloWorldScreen class is making a call to an unimplemented method in HelloWorldRepository. This is what HelloWorldRepository looks like so far:

public class HelloWorldRepository
{
	public String getMessage()
	{
		return null;
	}
}

Now let’s say you’re a good boy/girl and you buy into the whole TDD idea. So before attempting to implement HelloWorldRepository, you want to create a unit test. This is where the fun begins.

So let’s add the first unit test on you test package folder and let’s call the class HelloWorldRepositoryTest. It will have one test for HelloWorldRepository’s getMessage() and another method to hook up a test runner (more on that later). Here’s what the test class looks like:

public class HelloWorldRepositoryTest
{
	public void testShouldGetHelloWorldMessage() throws AssertionFailedException
	{
		HelloWorldRepository repository = new HelloWorldRepository();
		String message = repository.getMessage();
		Assertion.assertEquals("ShouldGetHelloWorldMessage", "Hello World", message);
	}
	
	public void test(int testNumber) throws Throwable
	{
		switch(testNumber)
		{
			case 0: testShouldGetHelloWorldMessage(); break;
			default: break;
		}
	}
}

Before we can run this test, we’ll need to do 3 more things.

  1. Add an alternate entry point to our HelloWorld project to be able to run our unit tests as a separate app.
  2. Add a way to report the results.
  3. Add a Test Runner, which will call our test(s).

Let’s do this.

Adding an alternate entry point for our tests

You could implement a different way to call the unit tests, but I prefer to have a separate app icon on your phone that launches the tests. This is why I added an alternate entry point for this example. If you use this approach in your project, you’ll obviously need to make sure to not include this on your deployment code, but I’ll leave that to you to figure out. In the meantime, this is what your main() method will look like after adding the new entry point:

public static void main(String[] args) 
{
	boolean startApp = false;
	boolean runTests = false;
	
	for (int i = 0; i &lt; args.length; ++i) 
	{
		if (args[i].equals("helloworld")) startApp = true;
		if (args[i].equals("helloworldtest")) runTests = true; // name of the alternate entry point for your tests app
	}
	
	if (startApp)
	{
	    	HelloWorld theApp = new HelloWorld();
	    	theApp.enterEventDispatcher();
    	}
	
	if (runTests)
	{
		HelloWorldTestRunner testRunner = new HelloWorldTestRunner();
		testRunner.enterEventDispatcher();
	}
}

Make sure to make the corresponding changes to BlackBerry_App_Descriptor.xml as well. Notice that this new entry point is calling our test runner. Let’s create it.

Adding a Test Runner

This is the class that will be called when the test app launches (through the alternate entry point). Its responsibility is to run the unit tests and delegate the test result reporting to the corresponding class. Here’s what it looks like for our example:

public class HelloWorldTestRunner extends UiApplication
{
	public HelloWorldTestRunner()
	{
		HelloWorldRepositoryTest repositoryTest = new HelloWorldRepositoryTest();
		try 
		{
			repositoryTest.test(0);
       		} catch (Throwable ex) {
            		System.out.println(" ---> "; + ex.toString());
            		ex.printStackTrace();
       		}
        
       		pushScreen(new UnitTestResultsScreen());
	}
}

Now the last step is to go ahead and create the test result reporting class.

Adding a Test Result Reporter

Straight up from the BUnit example (included in the downloaded zip file), just copy/paste the UnitTestResultScreen class in your test package folder. This is basically the screen that will show up with the test results summary.

Running the Test

At this point you should be able to compile/launch your project using the BB simulator. Once your simulator is up, you should see a new icon to launch your tests – it will have the name you gave it when you defined the alternate entry point on your Blackberry_App_Descriptor.xml. Launch it and you should get this screen:

failingTest

Great! You have a failing test with a descriptive message. You may be thinking whaaaat? Well, remember we’re doing TDD. You’re supposed to get a failing test first. Now let’s make it pass.

Making the Test Pass

To do this, let’s fix HelloWorldRepository.getMessage(). Here it is:

public class HelloWorldRepository
{
	public String getMessage()
	{
		return "Hello World";
	}
}

And let’s run the tests again. This time you should see your test pass:

passingTest

Voilà!

Going Forward

If you’re used to JUnit (or any XUnit framework for that fact), you may have noticed we did some things manually (like wiring up the test to the runner). Unfortunately, BB is based on J2ME, which doesn’t support Reflection, so you have to take care of managing the wiring. In our case that means you’ll have to update the TestRunner with any new tests you add. That’s a price you should be willing to pay, as the benefits unit-testing brings you can let you sleep really well at night (especially when your project starts growing).

Hooking up log4net to ASP.NET using HttpModule

October 14, 2010

Caveat: This post is more for future self-reference than anything.

A client recently asked us to troubleshoot an asp.net web app that was generating a exception upon validating/submitting a particular windows certificate. The trace log seemed to point to a problem with the certificate itself, but we didn’t have access to it. Unfortunately the existing validation code didn’t have any logging in itself to get more feedback. Another challenge was that this app was mainly written in php with a small web service api written in C#. The code throwing the exception was in this api, so we decided to add some log4net logging to help us with this task. Here’s a summary of what we did:

Configuring log4net

We tried multiple configurations we found on the web (via Web.config or even Global.asax), but here’s the one that worked for us:

Using a custom HttpModule:

    
public class Log4NetModule : IHttpModule
{
    private static bool _configured = false;

    public void Init(HttpApplication context)
    {
        context.BeginRequest += new EventHandler(context_BeginRequest);
    }

    void context_BeginRequest(object sender, EventArgs e)
    {
        if (!_configured)
        {
            InitializeLog4Net();
            _configured = true;
        }
    }

    public void Dispose()
    {
        // Do nothing
    }

    private void InitializeLog4Net()
    {
        var layout = new log4net.Layout.PatternLayout(@"%d [%t]%-5p %c [%x] &lt;%X{auth}&gt; - %m%n");
        var logfile = Path.Combine(Path.Combine(HttpContext.Current.Request.PhysicalApplicationPath, "Logs"), "log.txt");
        var rollingFileAppender = new RollingFileAppender
        {
            Threshold = Level.All,
            AppendToFile = true,
            Layout = layout,
            File = logfile,
            MaxFileSize = 1000 * 1024
            RollingStyle = RollingFileAppender.RollingMode.Date,
            DatePattern = "Date",
            StaticLogFileName = true,
        };

        layout.ActivateOptions();
        rollingFileAppender.ActivateOptions();
        log4net.Config.BasicConfigurator.Configure(rollingFileAppender);
    }
}

Note this line of code:
HttpContext.Current.Request.PhysicalApplicationPath
// This returns the app’s current dir. Use this instead of Directory.GetCurrentDirectory()

Using this approach, this is the only change needed in Web.config:

  <system.web>
    <httpmodules>
      <add name="Log4NetModule" type="E222.OrderValidationService.Log4NetModule,E222.OrderValidationService" />
    </httpmodules>
  </system.web>

Adding the log statements

After this, the logging statements were ready to be put in place. E.g.:

var log = log4net.LogManager.GetLogger(typeof(MyClass));
log.Debug(&quot;My debug message&quot;);

Using jquery to Communicate Between Browser Windows

March 24, 2010

Recently I ran into a scenario in which I wanted some update to happen on a browser window based on an event that happened on a child window (i.e., a popup that had been launched by the main browser window). I did some googling and found this jquery plugin: jquery.windowmsg-1.0.js

Here’s a little tutorial on how to use it.

In my case, since I only needed to communicate from the child window to the parent, this is what I had to do:

On the parent aspx, I added this JS snippet:

$.initWindowMsg(); // initializes the plugin
$.windowMsg('eventName',  function(message){
	// jquery to respond to the message coming from the child
});

On the child aspx, here’s the corresponding snippet:

$.triggerParentEvent('eventName')

That’s it. I actually wrapped the child aspx snippet around a jquery click() event for the intended HTML element, and voilà – everytime I clicked on that element on the child window a status update would happen on the parent.

Strongly-Typed UI tests

March 9, 2010

One of the advantages that writing UI test in the same language as the AUT is written, is the ability to use part of the same View logic to author your tests. Moreover, in our case, this has allowed us to strongly link our View page with our tests.

Here’s how:

StaticallyTypedUITests

Let me try to explain this better:

1. Leveraging Automapper

If you’re familiar with tools like WatiN or Selenium, you understand that an important part of testing your web pages is having unique identifiers on your page elements (via id, class, or any other XHTML valid attribute) that allow you to locate them on a page. Imagine having to do this manually for each page/element and keeping it updated with your test code. That’s a significant cost to your project. So the first thing that we did was to automate this generation, through Automapper, which we already were using to map our Domain Model objects to our UI Model ones (see diagram). All we did was to add a new implementation of IValueFormatter, called SpanWrappingFormatter, whose responsibility is to add an HTML span tag around the mapped elements with a unique identifier resolved from its member name via reflection. Here is what it looks like:

public class SpanWrappingFormatter : IValueFormatter
{
	public string FormatValue(ResolutionContext context)
	{
		string camelCaseMemberName = context.MemberName.ToLowerCamelCase();
		return string.Format(@&quot;<span  {0}??>{1}</span>&quot;, camelCaseMemberName, context.SourceValue);
	}
}

2. Strongly-typed views

After having the previous step, it is pretty easy to have ASP.NET MVC add the element identifiers we need for our UI tests, as they are now part of the UI model property values. Simply resolving to the property value on the view does the trick.

3. Strongly-typed UI tests via AutoPilot-dotnet

The last step is to have a middle layer in your UI test engine to help you locate page elements while resolving its corresponding identifier via reflection, based on the provided UI Model Type. In our case, mostly due to Nick Becker’s effort, we built a DSL framework that allows us to do that (via WatiN). If you’re interested in looking at the code for this framework, Mahendra Mavani has created a google project for it called AutoPilot-dotnet. With that in place, all we need to do is use this api in our UI tests in order to drive browser interaction (see diagram for a code snippet).

Lesson learned

This approach has allowed us to significantly speed up our UI test development time. The fact that we have leveraged different technologies to strongly link our UI Model to our UI/Acceptance tests, along with being able to use a fluent interface to drive them, make our UI test suite easier to create, more robust and more maintainable.

How to get started with Test Automation

March 2, 2010

A buddy of mine, who is in QA, recently asked me for advice on how to get started on test automation on an existing web application. If you’re on the same boat, here’s my advice:

  1. Start with small steps. Pick a test scenario (at the UI-level) that you want to automate that will give you a better perspective of the effort required. A great candidate is the (build deploy) smoke tests, as they tend to cover the most commonly traversed paths of your application. Plus it’s a test that you’re prone to use very frequently, so the re-usage tends to be great.
  2. After you have a scenario in mind, pick a tool to do the job. You may want to spend a little time researching this, but don’t overdo it. Don’t fall on the (waterfall-like) trap that “everything” has to be perfect from a design point before implementing code. I guarantee you that if you’re new to test automation, you will not have the necessary experience to pick the “best” tool for your job (if there were such a thing). So the best thing here is to do a little bit of tools research based on your system and start automating asap. To begin with, you may want to consider an open-source tool. They’re free and usually have plenty of online resources to help you along the way. They are also very reliable and use mainstream languages as their input (Ruby, C#, Java…) which may be appealing to your organization. I would suggest you start playing with either Watir (or any of its favors – WatiN, WatiJ…) or Selenium. One more thing: stay away from the record-and-play tools – their ROI is very low as their output scripts tend to have very low reusability, or they require heavy manipulation after creation to fit your long-term needs.
  3. Once you have a better grasp of UI-test automation, start familiarizing yourself with the application codebase (if you haven’t yet). Traditionally, testers never look at the code they’re trying to test (they operate in a more black-box manner). However, in my experience efficient test automation is done in a white-box manner. If you don’t know the language the application is written in, start with doing some googling on it. Nowadays, chances are the application is written in a OO language. If that’s the case, I would suggest you start with an easy-to-learn OO language to get a better grasp of those concepts in your head before jumping into more in-depth OO languages. If you asked me to give you a straight suggestion here, I would tell you start learning Ruby. Get a hold of the Pickaxe book and review as much of it as you can (with a hands-on approach). The purpose of all this is to give you a better approach on automating tests as a whole. You will probably come to realize on your own that you should not rely on UI-level tests only.
  4. Keep in mind that a test automation project should be treated as any other software project. You should consider best-practice software design and architecture principles like with any other relevant codebase. At various stages of its lifetime, it will require redesign, refactoring, maintenance… Basically, treat it as a first-class citizen, or otherwise it will grow up to be a maintenance headache with close-to-little ROI value. On this matter, search for guidance from more-experienced developers within your organization if possible. Discuss with them alternative design ideas. Show them your code every once in a while and get feedback from them. Get them involved in the automation effort.

Common misconceptions

  • a) Automation will replace manual testing:

Keep in mind that test automation should NOT and does NOT replace manual testing. There is plenty of research that proves this (read up on Cem Kaner’s material if you’re interested). So if you’re thinking that your test automation effort is going to replace manual testing, think twice. You may be taking a huge risk. What you should strive for is a good/intelligent balance between them (which will depend on your situation).

  • b) Automate “everything”:

I’ve heard this statement a few times before. IMHO, this is the wrong approach to test automation. When faced with this idea, consider what is “everything”? It would probably take you eons to figure out all the possible test scenarios your system can be faced with. Then, even if you were to figure them out, it would take you quite a long time to automate them all. Moreover, your system is a living/changing animal. By the time you realize it, your application will have changed so much that previous tests would be outdated at best or obsolete at worst. Instead, consider adopting a more pragmatic approach, especially when it comes to system-level tests. As mentioned before, an efficient automation approach considers automating tests at different levels (unit, integration, acceptance tests).

  • c) Automation will get rid of all bugs:

Like I said before, test automation is effectively a software project on its own; therefore, it is bound to have the same limitations and flaws – from design to implementation. Moreover, some of your scenarios will not be automatable (or simply not good candidates for it). On the other hand, some scenarios will be great candidates for automation. Expect bugs to still flourish even after having an automated test suite. However, learn from them to make your suite more robust. In my experience, having a strong automation suite makes an application way less buggy and enduring. Invest time and money on this front, and you won’t regret it.

Bypassing JavaScript dialogs for WatiN tests

February 19, 2010

As described in a previous blog post, we wanted to implement a practical way to disable JavaScript (JS) dialogs for our automated UI test environments.

At first, we were reading the configuration directly from the aspx pages that had some JS, in order to accommodate for the new behavior (a very non-DRY approach). Then we figured we could abstract that logic to some helper method and call the method from the aspx’s (a slightly better approach, but still not as simple as we’d like it to be). Then, one day, Jeffrey Palermo shouted “isn’t JS a dynamic language?”. And that was the key to our next approach.

With dynamic languages, it is very easy to override native function/method behavior. Simply declare a new function/method with the same name of the one you want to override (within the scope in which you want to use it), and implement your new desired behavior. I used to do this with Ruby, so it was easy for me to figure out how to do it in JS.

For example, in our case one of the functions we wanted to override was confirm(). All we had to do was add this piece of code in our master pages and voila:

<% if (ObjectFactory.GetInstance<iconfiguration>().ShouldAdaptToUiTesting()){ %>
	<script language="javascript" type="text/javascript">
		/* <![CDATA[ */
			function confirm() { return true }
		/* ]]> */
	</script>
<% } %>

What this is saying is basically, always return true when your page asks for a JS confirmation from the user if you are working in a UI-test environment. What it does is it bypasses any JS confirm box when clicking on an element with this event, as if the user had clicked OK on it. Once we had this in our master page, all of our application pages would automatically inherit this behavior. No more need to have a helper method, or for that matter, having to remember to invoke some other code when creating the aspx’s in order to do this. IMHO, this is a more elegant and simple way to handle this situation.

Here’s a broader diagram explaining the approach we used:

OverridingJavaScriptDialogsInAspNetMvc


Follow

Get every new post delivered to your Inbox.