• Controllers of a web app usually need the dependent services being injected through constructor via an IoC container. In order to test the controllers, many dependent services need to be mocked, and service calls stubbed.

    In most cases, only few of the mocked services are really important for a specific test, and for other controllers, we duplicate similar setup routines in different test classes. These duplicated routines lower the readability of the tests.

    While working with Raymand days ago, we tried to manage mock dependencies with Unity container. Here demonstrates the way we used.

    ControllerDependencies manages all dependencies used for controllers.

    public class ControllerDependencies
    {
      private readonly IUnityContainer container;
     
      // named mock services are ready for setting up further expectations in test
      public readonly IPolicyService PolicyService;
      public readonly IQuoteService QuoteService;
      // other services
     
      public ControllerDependencies()
      {
        container = new UnityContainer();
         
        PolicyService = MockRepository.GenerateMock<IPolicyService>();
        QuoteService = MockRepository.GenerateMock<IQuoteService>();
        // create other mocking instances
        
        container.RegisterInstance<IPolicyService>(PolicyService);
        container.RegisterInstance<IQuoteService>(QuoteService);
        // register other mocking instances
      }

      // create a controller instance for test
      public T Create<T>() where T : Controller
      {
        return (T) container.Resolve(typeof(T));
      }
     
      public void VerifyAll()
      {
        PolicyService.VerifyAllExpectations();
        QuoteService.VerifyAllExpectations();
        // verify against other mock instances
      }
    }


    Below is a test.

    [Test]
    public void SomeActionShouldDoSomething()
    {
      var dependencies = new ControllerDependencies();
      // setup expectation againt named services if needed
      dependencies.QuoteService.Expect(r => r.GetQuote("quoteNumber")).Return(new Quote());

      var policyController = dependencies.Create<PolicyController>();

      var actionResult = policyController.SomeAction();

      // asserts go here
     
      dependencies.VerifyAll();
    }


    ControllerDependencies is reusable for other controllers and could also be the place you put common codes for stubbing the service calls.

     

  • This is yet another way of writing selenium test, which targets making 80% of the test codes more expressive, succinct and noise-free.

    Problems of the normal selenium tests

    • type(), select()..., these selenium commands are in detail and wordy for complex form, test is hard to follow.  
    • test data tends to be weaved into selenium code, hard to be reused in a clear way.  
    • Thread.Sleep() and WaitForCondition() as a work around for timing issue mess up the codes.  
    • IDs or element locators are duplicated from the client side and spreaded everywhere in selenium code.
    • hard to catch javascript exceptions of the client side from selenium code.

     

    In a word, pure testing logics tend to be messed up with other noisy codes for different reasons.

    How it works

    jQuery.parcel is a young jQuery extension designed for better javascript encapsulation. One of the key features is getting/setting state of a part of web page through JSON object. When setting state, that part of page is populated with proper events fired just like real user interaction. This feature enables the new way of writing tests.

    In selenium code side, model class is created to represent a group of fields in page and the instance of model class is serialized to JSON, then send to selenium RC for page populating through selenium RunScript command. page state goes back to selenium code in a similar way.

    A 'Hello World' sample

    State getting/setting through jQuery.parcel

    Given a HTML snippet:

    <div id="person">
      <input name="name" type="text" />
      <select name="age">
        <option>please select</option>
        <option>18</option>
      </select>
      ...
    </div>
    

    Then

    $("#person").state();

    Returns {name: "", age: "please select", ...} as the state of the person div.

    $("#person").state({name: "luning", age: "30"});

    Input fields in person div are populated in proper order and with proper events(click, change, blur,...) fired. The name of the property in state matches the name of the input.

    state() can be called on any jQuery object including div, fieldset, input and so on.

    Model class in selenium code

    (C# for the following sample codes)

    public class PersonModel
    {
        public string name;
        public string age;
        ...
    }


    Choose a JSON serializer, compose javascript and run it through selenium

    Use any JSON serializer(JSON.Net, JavaScriptSerializer) you like to do the two way serialization.

    PersonModel model = new PersonModel{
                            name = "luning",
                            age = "30"
                        };
    string json = new JavaScriptSerializer().Serialize(model);

    Then, json string is sent to browser for page population.

    void Populate(string containerSelector, object model)
    {
        string json = new JavaScriptSerializer().Serialize(model);
        selenium.RunScript(string.Format("$('{0}').state({1});", containerSelector, json));
    }
    
    Populate("#person", new PageMode{
                            name = "luning",
                            age = "30"
                        });
    

    Code to get state from page

    T GetModel(string containerSelector)
    {
        var json = selenium.GetEval(string.Format("$('{0}').state();", containerSelector));
        return new JavaScriptSerializer().Deserialize<T>(json);
    }
    
    PersonModel model = GetModel<PersonModel>("#person");

    By now, we see the basic idea of how to write selenium tests with jQuery.parcel.

    More than 'Hello World'

    Above is a very simple 'Hello World'. In order to write full-fledge tests for complex pages, we need to leverage other features of seting state and create some javascript helper functions for testability. Here are some topics about this.

    More control on setting state

    Options are available as the second parameter of state(), which are useful for testing purpose, they are:

    • sync, true will turn off jQuery animation and run jQuery ajax in sync. This is useful if page has many async behaviours, and Thread.Sleep() and WaitForCondition() are no longer needed in this case.  
    • editable, true will check that the target field is visible and enabled before setting state.  
    • verify, true will check that the value is actually set as expected after setting state.  
    • exist, true will check that all properties in JSON object have corresponding fields in page.

     

    The new version setting state becomes:

    $("#person").state({name: "luning"}, {sync: true, editable: true, exist: true, verify: true});

    If any of the conditions is not satisfied, exception will be thrown in client side and eventually captured in selenium code. This is quite helpful for debuging.

    get/set state is not enough for all purposes

    Approximately speaking, 80% of the testing logic is about populating some fields, clicking something and verifying some other fields. 15% can be done by verifying the attributes(not just value) of a field. For the 5% left, we do them as the way we did them before.

    Some handy methods are needed in javascript which are used solely for testability. Here are two of them:

    • A javascript function returning attributes of a field as JSON is probalily the most useful one. Attributes may include common attributes of a DOM element like class, visibility and enabled, and also some attributes which are only meaningful for some particular type of input(eg. all options of select). Build corresponding class in selenium code and deserialize the JSON to it.  
    • A javascript function returning all errors of the page is another useful one for testability.

     

    The final test looks like:

    With the facilities above, the final test may look like below.

    ...
    page.Populate(new PersonModel{
                      name = "luning",
                      age = "please select",
                      // ...
                  });
    page.Confirm(); // click some button
    var errors = page.GetErrors(); // call javascript function to get errors on page
    Assert.AreEqual("age should be selected", errors);
    ...
    page.Populate(new PersonModel{
                      fieldA = "A",
                      fieldB = "B",
                      // ...
                  });
    var model = page.GetModel();
    Assert.AreEqual("some value", model.anotherField);
    ...


    Advantages compared to normal way of writing selenium tests

    get/set state rather than detail steps

    New way comes with a high level concept of state/model of page, and is able to populate fields or get state of fields in batch. This makes code more expressive and succinct expecially for complex form.

    Minimize duplication of ID and locator

    Test depends on field name, and it will notify us if name in model doesn't sync with name in DOM, because exception is thrown if name doesn't match any DOM element.

    Minimize the housekeeping codes

    Thanks to option sync of setting state, which makes test free from noisy housekeeping codes like Thread.Sleep() and WaitForCondition().

    Quicker

    Populate with state results in less round trips between selenium code and browser.

    Don't let off any javascript exception

    Javascript exceptions are catchable from selenium code while populating page, like exceptions in case of error in event handler or ajax callback, field name typo in model, setting state against invisible or disabled field or failing to set state to expected value. These help developer locate problem quickly.

    Easy to manage reusable test data

    Test data can be expressed as a model instance or a JSON string, and is easy to be extended or inherited. It can also be stored in txt file and deserialized into code easily. This is expecially useful for reusing test data of complex form.

  • Mark Needham just posted a blog here described the 'waiting for jQuery ajax call' problem in selenium tests and the way we solved it.

    The basic idea is recording the count of active ajax requests in client side js code, and generically decorating the calls(click, type, select etc.) in selenium tests with the logic of waiting for the count to be zero.

    Ajax request may not be the only async point we want to wait for its completion in selenium tests, animation is another one we care about, but just turn off it in tests so that we don't need to worry about it any more. "jQuery.fx.off = true" will turn off jQuery animation.

    Is there any more async points? probably YES. Acturally, what we really want to wait is the completion of any action which is delayed to be executed by window.setTimeout() or window.setInterval(). Ajax and animation rely on window.setTimeout() or window.setInterval() to simulate the async behaviours eventually.

    Please check out the code at mark's post or here(with comments) for details. It works for the cases you fire multiple ajax requests at once or fire further ajax request in previous ajax request's callback.

    Given this, we removed almost all noisy thread.sleep() and waitForCondition() codes in selenium tests! The build is speeded up and the tests become more concise, readable and stable.

    This approach is simple, stable, side-effect free and able to be ported to other ajax framework easily.(jQuery Ajax provides proper events we can rely on, for other ajax framework without build-in events, we can try method delegation instead)

    Waiting for ajax call is a common issue in selenium tests, try this approach and make your selenium tests cleaner.

  • My Object Mother is easily messed up with overload methods

    Object Mother is usually used as a test fixture to create objects for testing purpose. e.g.:

    Contact contact = ContactMother.CreateContact();

    A typical simple contact will be assembled through the call. As project goes on, ContactMother may probabily looks like below:

    CreateContact(string firstName, string lastName)
    CreateContact(string firstName, string lastName, string organizationName)
    CreateContact(string organizationName, string email)
    ...

    Every reasonable combination of parameters may want to overload the method. The class is messed up and becomes hard to use and maintain.

    .NET 3.5 Object Initializer could do a better job than overload methods

    Object Initializer is one of the language enhancements of .NET 3.5, you can create object like this:

    SomeObject object = new SomeObject{Property1 = "foo", Property2 = "bar"};

    It's a short version of creating object with default constructor and setting properties as your needs.

    You may have the feeling that we could create our parameter combination with this much flexible manner.

    Create an Object Builder which holds properties used for creating object

    public class ContactBuilder
    {
    public string FirstName {get; set;}
    public string LastName {get; set;}
    public string EMail {get; set;}
    public string OrganizationName {get; set;}
    // other customizable properties may be used by tests

    public ContactBuilder()
    {
    // set all to default value
    FirstName = "foo";
    LastName = "bar";
    EMail = "foobar@abc.com";
    OrganizationName = "ABC";
    // set other properties...
    }

    public Contact Build()
    {
    // create dependent objects including Organization
    // assemble the final contact with the properties and return it
    }
    }

    Then, contact can be created with any parameter combination:

    Contact simpleContact = new ContactBuilder().Build();
    Contact foobar = new ContactBuilder{FirstName = "foo", LastName = "bar"}.Build();
    Contact contactWithOrganization = new ContactBuilder{OrganizationName = "Freeway"}.Build();
    ...

     

    Combine with a Call-Chain style builder

    Typically, Object Builder build object as below:

    Contact contact = new ContactBuilder()
    .WithName("foo", "bar")
    .WithEmail("foobar@abc.com")
    .Build();

    The trick is obviously returning 'this' in all WithXXX methods.

    The object initializer style builder is very similar as the call-chain style builder, and some time it's meaningful to combile these two. e.g. if you want to add common behaviours into builder as well, like this:

    Contact foobar = new ContactBuilder{FirstName = "foo", LastName = "bar"}
    .AttendAMeeting("Sales Meeting")
    .Build();

     

  • 这是一个基于JSF的WEB应用,被测的场景是编辑一个巨大的表单,然后进行预览操作,最后再回到编辑页面,验证各个字段是否和以前的一样,据此间接检验各个页面元素与后台Bean的绑定是否正确。

    以前的测试不是人读的

    这是之前实现这一测试的代码片段:

    @Test
    public void createFullRequest_priview_backEditing_checkData(){
    goToCreationPage();
    browser.click(ADD_APPOINTMENT);
    browser.click("lorryTrucking1");
    browser.select("containerSizeType1_1", "label=20' Platform");
    typeAndBlur("containerQuantity1_1", "1");
    browser.select("cargoPackageType1_1", "label=Bar");

    ......

  • 最近的一个Web项目大部分的逻辑都是客户端页面逻辑,主要是通过Javascript实现的,如何进行高覆盖率的单元测试是我们面临的一个问题。

    分 析一下,有两种逻辑需要测试,一个是与服务器交互的页面操作,比如提交表单后跳转到另一个页面,这很适合写Selenium测试。这里关注的是另外一种, 即客户端页面逻辑,它与服务器没有交互,比如页面Dom元素的联动变化和数据校验逻辑等,这部分当然也可以写Selenium来测,而且由于不与服务器打 交道,组织得当的话速度也很快。但此时Selenium测试与代码实现的反馈距离太远,不方便组织细粒度的测试,更重要的是写这个测试对 Javascript代码的设计没什么帮助,因为再烂的Javascript实现可以方便地写出Selenium测试。

    对于客户端页面逻辑,我们尝试使用Jsunit进行测试。对于没有Dom操作的纯Javascript函数,测试很容易。对于有一定复杂度并有Dom操作的逻辑,我们将他们封装成Javascript对象并用Jsunit测试它。

    一个具体的例子

    上图是页面的一部分......

  • Q:单元测试的主要作用有哪些?

    A:单元测试的作用主要有:
       (1) 确保代码实现了预想的逻辑。这是所有测试都有的,也是最重要的功能。
       (2) 确保重构不破坏现有的功能。所有测试都或多或少地支持这一功能,有些“重构不友好”的测试在重构过程中可能会被删除或修改。
       (3) 驱动出设计,主要是帮助识别出类或接口函数。这是个一次性的好处,只有部分测试会起到这个作用。那些直接保证内部函数实现逻辑的测试起不到这个作用。
       (4) 当难以编写满意的测试时,提示开发人员现有设计的问题并鼓励他们重构现有的代码。这也是个一次性的好处,只有部分测试会起到这个作用。
       (5) 作为需求文......