How can I get a better testability of an SAPUI5 application? The essential precondition for efficient unit testing, a more adaptable application and better code is to master the handling of dependencies. For more background information about the general principles of Dependency Management, see a blog post by Martin Fowler: http://martinfowler.com/articles/injection.html

and for more information about Test Doubles, see a blog post by Gerard Meczaros:

http://xunitpatterns.com/Using%20Test%20Doubles.html.

In the following, four techniques are shown how to inject test doubles: View Constructor Injection, Controller Setter, Overwriting global Objects and Adapter.

First, the view constructor injection allows injecting an object into the view with the parameter viewData. This allows replacing objects, which are already needed before the controller is instantiated. This could, e.g., be the case for the resource bundle. In the following example, a Test Double of the Shell is created and injected using the view parameter viewData.

setup injects Test Double via viewData Parameter

    var assignmentPage = sap.ui.view({

      viewName : “ViewName” ,

      type : sap.ui.core.mvc.ViewType.JS,

      viewData : oTestDoubleFactory.createShellTestDouble()

    });

Second, the controller setter allows injecting the object into the controller with a setter method.

setup injects TestDouble in Controller

this.oAlertActionAdapter = oTestDoubleFactory.createAlertActionAdapterTestDouble();

this.oController = assignmentPage.getController();

this.oController.setAlertActionAdapter(this.oAlertActionAdapter);

Third, a global object like OData can be overwritten. However, this technique is not recommended, because it could break other tests, which depend on the original state of the object. Therefore, the test should put the original object into a variable and afterwards revert to the original state of the object. But avoid this technique. You should avoid globale state and singletons as far as possible and design for good test isolation from the beginning. Otherwise it takes later a lot of effort to get the overall application testable.


     setup saves original state and injects TestDouble

             this.odata_request_original = OData; //remember original state

          OData = oTestDoubleFactory.createODataTestDouble();   

     teardown reverts to original state

          OData = this .odata_request_original; //revert to original state

    

Fourth, an alternative is the wrapper or adapter pattern combined with the parameter injection. This avoids the disadvantages of overwriting global objects. AlertActionAdapter, for instance, encapsulates all OData batch requests with regards to alerts. So the controller calls the AlertActionAdapter method assignAlerts instead of building and firing OData Batch Request. In the test, an instance of OData Test Double can be created and passed into the wrapper method assignAlerts with parameter injection.

     setup create TestDouble

this.oModelTestDouble = oTestDoubleFactory.createODataModelTestDouble();

    

     test function calls assignAlerts with TestDouble

        this.oAlertActionAdapter.assignAlerts(this.oModelTestDouble, this.aAlerts, “MEI” );

  

     productive implementation of assignAlerts

      this.assignAlerts =

          function(oModel, aAlertIDs, sUserName, fnSuccess, fnError) {

            var aBatchOperations = [];

            for ( var i = 0; i < aAlertIDs.length; i++) {

              aBatchOperations.push(oModel.createBatchOperation(

               “/SetResponsiblePerson?AlertID='” + aAlertIDs[i].alertID +

   “‘&ResponsiblePersonID='” + sUserName + “‘”, ‘GET’ ));

    }

    oModel.addBatchReadOperations( aBatchOperations);

    oModel.submitBatch( function(oData, oResponse, aErrorResponse) {

fnSuccess(aErrorResponse);

}, function(oError) {

fnError(oError);

    }, false);

};

This blog post is part of a series, like the following blog post to stay tuned and get updates about more topics around software engineering with SAPUI5 and JavaScript:

http://scn.sap.com/community/developer-center/front-end/blog/2013/12/12/engineering-in-javascript

To report this post you need to login first.

4 Comments

You must be Logged on to comment or reply to a post.

  1. John Patterson

    Hi Klaus

    Thanks for sharing, it is a very interesting topic.

    I cant help but think this blog would have been a lot more effective if you provided tactile real world examples which related to building UI5 apps, preferably using qunit and sinonjs.

    Cheers

    JSP

    (0) 
    1. Klaus Haeuptle Post author

      Hi John,

      I absolutely agree. Currently, I am not allowed to publish the source code, since the RTC of the application has not taken place yet and building a separate example application takes some time.

      Hopefully we can integrate the approaches of the different blog posts in a smaller example application. But this will take some time.

      Thanks,

      Klaus

      (0) 
      1. HP Seitz

        Hi Klaus,

        I think the point from John is important. Can’t you use simply one of the nice demokit apps which are also shipped with OpenUI5 (like POA or the Shopping card example, there are already in the folder test-resources 😉 : test-resources/sap/m/demokit ) so it should not be any legal issues with this.

        Or something like UI5 Boilerplate

        Thanks, HP

        (0) 

Leave a Reply