View Ravichandran J.V.'s profile on LinkedIn RJV 's Blog Tweet @ravichandranjv

Translate

Monday, 25 August 2014

What to Unit test?

Going by the book is not really encouraged in today's wildly advancing technology world. If you, do, it will most probably leave you staring at the behinds of many. :)

Best way to keep yourself ahead is to be really good in your skill set; if it is a programming language, be on top by participating in discussion forums and communities. This will help knowing about scenarios that may never appear in your own project or lifetime.

Close to what I am getting at is this definition of unit tests by Martin Fowler -
Like most software development terminology, however, it's very ill-defined, and I see confusion can often occur when people think that it's more tightly defined than it actually is. 
First and foremost,  what to unit test depends on your commitment to testing. If you are very committed then chances are that your code coverage will be good. But over and above this,  you also need the skill with the unit test tool. For instance, the most common statement possibly used by almost all programmers across the world is the if (!fileExists) or within a try...catch block.

Is this statement testable? Should it be tested? To answer the second question first, the reason the answer is 'Yes' is because the line of code is expected to throw many exceptions -  DirectoryNotFoundException, FileNotFoundException and (yes) etc...So, the first question becomes important - is it testable?

Again, the answer is 'Yes' (left out italicizing it to make it more interesting! :)) but if you really do not know any syntax of existing unit test tool, how to write the test?

This question has always seemed important to me (to make a programmer move from the "Code-first syndrome" to a "Test-first-and-let-the-test-tell-you-what-code-to-write avatar") and so, I decided to list (well, sharing just one technique now (how to get and test a list of files from the file system in a unit test)...will share more later) here some of these common scenarios.

Aside from helping the code achieve the necessary quality benchmarks, unit tests should also be efficient and lean so that it does not weigh down the overall build or CI framework.

So, to write a unit test in the 'file exists' scenario,

1. If not file exists

Scenarios - as many as there are files (wild possibilities! :)) in a specified directory.

So, the unit test will want a list of files against which to test for some criteria.

The code will be something like this -

using System.Collections.Generic;
using System.Linq;
using System.IO;
namespace NUnit_Tests
{
    public class ReadFiles
    {            
        public List getListOfFiles()
        {
            string[] filePaths=null;
            filePaths = Directory.GetFiles(@"c:\cambridge\");
            return filePaths.ToList();
        }
    }
}

In  NUnit, here is an example of how to test the method most efficiently and ALSO in such a way that maximum scenarios can be tested with this approach !!

using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
namespace NUnit_Tests
{
    [TestFixture]
    public class Class1
    {
        ReadFiles objInstance;
        string[] filesToExist = { "abc.jpg", "a.htm" };
        [Category("LongRunning")]
        [Test]
        public void LongRunningTest([ValueSource("Files")] string filePath)
        {
            Assert.That(Files.ToList().LastOrDefault(),Is.EqualTo("zzz.jpg"));
        }

        private IEnumerable Files
        {          
            get
            {
                objInstance = new ReadFiles();
                return objInstance.getListOfFiles();
            }
        }
    }
}

The snapshot below shows the number of scenarios (equivalent of unit tests / asserts in NUnit or unit testing tools) that are now possible with this approach.



For example, you could test if the path is returned correctly with Is.SamePath or can test the number of files existing or if a particular file has a required extension and the possibilities are endless.



Sunday, 24 August 2014

KnockoutJS and AutoPostBack="true" - I

I had to check this out. What could be the difference if the developer were to use KO and not ASP.Net?

The only difference is the programming language of use - C# or jQuery / Javascript.

The resultant output is this below


No button click event just the AutoPostBack property of the drop down list set to true.

I will first share the ASP.Net code and then dwell into the equivalent KO code.

You need JSon.Net installed and referenced to the project, an app_id to consume the JSon data resultset from openexchangerates.org, VS 2012 for web and you are good to go.

The HTML source of the .aspx page

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="GetExchangeRates.aspx.cs" Inherits="GetExchangeRates" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    
        Currency  
        <asp:DropDownList ID="DropDownList1" runat="server" AutoPostBack="True" OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged">
        </asp:DropDownList>
  
        <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>

    
    </div>
    </form>
</body>
</html>


Here is the aspx code behind.

using System;
using System.Collections.Generic;
using System.Net;
using Newtonsoft.Json;
    public partial class GetExchangeRates : System.Web.UI.Page
    {
        static JSon_SampleData.CurrencyRates obj;
        Dictionary rateValues;
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                obj = new JSon_SampleData.CurrencyRates();
                obj = Download_Serialized_ExchangeRate("http://openexchangerates.org/api/latest.json?app_id=");
                rateValues = new Dictionary();
                rateValues = obj.Rates;
                foreach (var raate in rateValues)
                {
                    DropDownList1.Items.Add(raate.Key);
                }
                Session["rateValues"] = rateValues;
            }
        }

        private static T Download_Serialized_ExchangeRate(string url) where T : new()
        {
            using (var w = new WebClient())
            {
                var json_data = string.Empty;                
                try
                {
                    json_data= w.DownloadString(url);
                }
                catch (Exception) { }
                return !string.IsNullOrEmpty(json_data) ? JsonConvert.DeserializeObject(json_data) : new T();
            }
        }

        protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
        {
            rateValues = (Dictionary)Session["rateValues"];
            foreach (var raate in rateValues)
            {
                if (raate.Key == DropDownList1.SelectedItem.Text)
                {
                    TextBox1.Text = raate.Value.ToString();
                    break;
                }
            }

        }
}


And the Class to hold the JSon data.

using System.Collections.Generic;

namespace JSon_SampleData
{
    public class CurrencyRates
    {
        public string Disclaimer { get; set; }
        public string License { get; set; }
        public int TimeStamp { get; set; }
        public string Base { get; set; }
        public Dictionary Rates { get; set; }
    } 
    
}

Reference the JSon Data class in your ASP.Net website.

I will post the KO code in the next part and get back to the BDD and Agile part.

Saturday, 23 August 2014

KnockoutJS, Jasmine but why PhantomJS ? - II

However, since Jasmine is based on testing Behavior against expectations, it is necessary to mention Behavior Driven Development (BDD) and the artifacts that matter for BDD like user stories, scenarios and enhancing code quality through better testability provided by tools like Slim (which enable creation of Scenarios and testing them (thereby, increasing the quality of code because in Agile, the simple thumb of rule is, the more testable the code, the better the quality of code.)), this brings us to the most relevant point of them all (that which is directly related to Agile) - how to select the right tool for an Agile team, not in terms of technical correctness but in terms of fitting in with the underlying development model!).

The tool must be selected in accordance to the basic principles of the model. For instance, BDD stresses on testing behavior foremost so Jasmine, Slim. But what about KnockoutJS?

KnockoutJS is the most compatible tool for an Agile development model like BDD because it allows for testing the changes to the View through the ViewModel ! This does not mean that to be Agile-compatible, a language has to provide for measures to test its view through the viewmodel but that the abilty to abstract the viewmodel away from the view allows for testing 'model' code independently!

To make it more clear, in HTML, if you were to enable instant change reflection to the client page, you will have to wire the onchange or keyup event for the control but can you test if it is working correctly? No. Because the code is wired within the HTML DOM and although there may be ways to access the HTML DOM (so to say), it is cumbersome, not possible to test independently and not suited for Agile. It is more like how fitNesse was used in .Net - contrived and hard-wired.

In the previous part, the reference to PhantomJS's console runner was only to enable GUI reporting of the Jasmine tests.

But, having said, it is not just for a web UI based test report that you need to use another tool; you could as well use the Jasmine test runner and achieve the same results as below:


The script is the same (as in part I) except that the Jasmine Test runner's HTML will no longer refer to PhantomJS's ConsoleRunner but instead to Jasmine's HTMLReporter !

Below is the HTML for the Jasmine's Test Runner.

<!DOCTYPE HTML>
<html>
<head>
  <title>Jasmine Test Runner</title>
  <link rel="stylesheet" type="text/css" href="Jasmine\lib\jasmine-1.2.0\jasmine.css" />
    <script type="text/javascript" src="Jasmine\lib\jasmine-1.2.0\jasmine.js"></script>
    <script type="text/javascript" src="Jasmine\lib\jasmine-1.2.0\jasmine-html.js"></script>
     
  <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
  <script type="text/javascript" src="knockoutjs.3.2.0\content\scripts\knockout-3.2.0.js"></script>
  <!-- SOURCE FILES -->
  <script type="text/javascript" src="helloko-script.js"></script>

  <!-- TEST FILES -->
  <script type="text/javascript" src="helloko-script-spec.js"></script>
</head>
<body>
<script type="text/javascript">
    (function() {      
        var jasmineEnv = jasmine.getEnv();      
        jasmineEnv.updateInterval = 1000;      
        var htmlReporter = new jasmine.HtmlReporter();      
        jasmineEnv.addReporter(htmlReporter);      
        jasmineEnv.specFilter = function(spec) {        
            return htmlReporter.specFilter(spec);      
        };
      
        var currentWindowOnload = window.onload;      
        window.onload = function() {        
            if (currentWindowOnload) {          
                currentWindowOnload();        
            }        
            execJasmine();      
        };      
        function execJasmine() {        
            jasmineEnv.execute();      
        }  
    })();
</script>
</body>
</html>

Alright, but what exactly am I driving at?

That, this much has only been unit testing of code.

If you want to use an Agile development method like BDD or TDD, the reporting plus the test tools themselves may have to be different due to many other artifacts of the Agile development life cycle like CI, E2E, Code Coverage etc.

And this is where tools like Slim come in. If you have already read my earlier post on using Jasmine and Slim, then the next part will have nothing new.

Next part - how to use Slim with KnockoutJS and Jasmine to enable BDD.


KnockoutJS, Jasmine and Phantom - I

What AngularJS or Javascript with RegisterClientScript blocks could not do, KnockoutJS does and satisfactorily simply !!

What this means, in Asp.Net terms, is equivalent to setting AutopostBack=true or using a jQuery callback function.

Working on client-server technology, especially for Asp.Net developers, frequently makes one think, "If only the code did not do so many round-trips to the server with post-backs and could do simple UI changes that reflect back instantly to the user...".

I mention this, not as a declaration of my own long-felt personal wish but, because this is what the KnockoutJS documentation or the help resources miss out that does not make more ASP.Net developers take to KO nor is there sufficient mention that because it is plain Javascript, it helps Agile development methods to quickly tap into the many already available unit testing and functional testing tools like Jasmine, Slim or PhantomJS and set up a robust team of "high speed development" corridors!

KO also makes things more interesting to the technical-jargon-smitten-adrenaline junkies, who must have a technical discussion on design patterns and architecture to even say "Hello World!" !.

Because KO enables client-client 'post', it means a fresh look at the way the view-model works and is understood in MVM becomes important - now, it becomes MVVM (the additonal 'V' in the model is actually viewmodel together).

The additional tier in the architecture is ok, not as a compromise that you cannot do anything about anyway, but seriously as an efficient workaround that not only improves performance but also helps Agile immensely!! How?

With and because of KO, you do not need to think of Selenium as an additional tool to burden your team with because testing the VM itself with Jasmine or other unit testing tools should suffice !!

And also, there is no need to learn an additional tool like Slim to integrate your tests because PhantomJs provides a command-line executable (or rather, an executable).

That is a lot of advantages of KO, I hope I am not putting down other equally or more efficient language tools. Yes, KO is not a framework as AngularJS probably is.

So, here goes as I whet my appetite...

HelloWorld.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Hello, KnockoutJS</title>
  <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
  <script type="text/javascript" src="knockoutjs.3.2.0\content\scripts\knockout-3.2.0.js"></script>
    <script type="text/javascript" src="HelloKO-Script.js"></script>
</head>
<body>
    <p>First name: <input data-bind="value: firstName" /></p>
    <p>Last name: <input data-bind="value: lastName" /></p>
    <h3>Hello, <span data-bind="text: fullName"> </span>!</h3>
  </body>
</html>

Of course, the reference to the jQuery script is still necessary because of the $ functiion callback in the below script.

And the Knockout script (and no pun intended!)

// HelloKO-Script.js

var HelloViewModel = function (firstname, lastname) {
    var self = this;

    self.firstName = ko.observable(firstname);
    self.lastName = ko.observable(lastname);

    self.fullName = ko.computed(function () {
        return self.firstName() + " " + self.lastName();
    }, self);
};

$(function () {
    ko.applyBindings(new HelloViewModel("Ravichandran", "Jv"));
});

Simple four terms to explain is all that is required - the ViewModel that is, quite apparently, the viewmodel, the observable method of KO that 'observes' the 'fields', the computed keyword of KO to take an action   and the applyBindings that applies - here is the magic! - the KO bindings, in this example the 'data-bind' to the 'value:' binding.

The above program will simply output this - 


But the magic is when you make any change to either of the field and,

The applyBindings is what activates KO and the callback magic with the help of the $ jQuery callback mechanism to make the UI update happen!

You can download KO separately or use the NuGet tool in VS 2012. I used the latter - copy the package after downloading with NuGet into the relevant folder and modify the script src path.

The Jasmine tests are equally simple !

All you need in Jasmine is a spec file (same name as the CUT or Script Under Test) and the Jasmine framework.

The spec file

"HelloKO-Script-spec.js"

describe("My Name", function () {
    it("concatenates firstName and lastName and displays full name", function () {
        var target = new HelloViewModel("Ravichandran", "Jv");
        expect(target.fullName()).toBe("Ravichandran Jv");
    });
});

The describe keyword describes the function and gives it a name as parameters, defines a target variable 'target' and calls the 'expect' method of the Jasmine framework to match a given value with a call to the HelloKO-Script.js method, fullName().


To run and see the test results, you could use your own CSS or PhantomJS or Slim.

Step 1
Download Jasmine and PhantomJS and place the downloaded folders in the bin/root or wherever you have the HTML page.

Step 2
Create a new HTML page and insert the below code -

<!DOCTYPE HTML>
<html>
<head>
  <title>Jasmine Test Runner</title>
  <link rel="stylesheet" type="text/css" href="Jasmine\lib\jasmine-1.2.0\jasmine.css" />
    <script type="text/javascript" src="Jasmine\lib\jasmine-1.2.0\jasmine.js"></script>
    <script type="text/javascript" src="Jasmine\lib\jasmine-1.2.0\jasmine-html.js"></script>

    <script type="text/javascript" src="phantom-jasmine-master\lib\console-runner.js"></script>
  <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
  <script type="text/javascript" src="knockoutjs.3.2.0\content\scripts\knockout-3.2.0.js"></script>

  <!-- The KnockoutJS script source file -->
  <script type="text/javascript" src="helloko-script.js"></script>

  <!-- The spec Jasmine file -->
  <script type="text/javascript" src="helloko-script-spec.js"></script>
</head>
<body>

    <!-- The Phantom script to invoke the console0runner -->
<script type="text/javascript">
    var console_reporter = new jasmine.ConsoleReporter()
    jasmine.getEnv().addReporter(new jasmine.TrivialReporter());
    jasmine.getEnv().addReporter(console_reporter);
    jasmine.getEnv().execute();
</script>

</body>
</html>

That is it! Run the above HTML page and see the results. If your steps 1 & 2 were correct, you should see the below result screen else make sure the <script tags' src location are matching with your path.

If you do not like the PhantomJS script, you could use Slim instead but for that you will need to download Slim, know how to use and start the fitNesse server, write the Slim test suite and finally run the Slim fixture !!

With PhantomJS, you modify just the TestRunner HTML page as and when you need to modify the path to the script source file and the Jasmine spec file.

Ideally, they say, you should mock the jQuery $ method, too, but that, again, as they say, is yet another story - more in the context of TDD !

Tuesday, 19 August 2014

Angular.Js - Funny parser !!

You will need a HTML5 compatible browser to try this but it will be sure to rock you.

The funny part is line # 5. You are welcome to leave funny or witty comments. Please do not get overboard over the technical aspects, though.

If you remove the line, the result will be 5 !!!


The code:

1. < !doctype html >
2. < body >
3. < div ng-app="" ng-init="quantity=1;cost=5" >
4.

5. < p > {{quantity=quantity+1}} < /p >
6. Total in dollar: {{ quantity * cost }}
7.

8.

9.
10.


But the same when used within the scope of an angular module will work predictably as below. This is because the
tag that was the application's main entry point in the above scenario (where ng-init is initializing the 'quantity' variable but the increment was happening inside an AngularJS expression), is now being used as a controller by the module. 


The $scope of the controller is the application (the div tag) it is referred from.


But the good thing is that there is no index out of bounds exception and so the control moves to the next line even if the index used for an array element is out of bounds !!

And, the best part is it works like the good old pointers !!



Result is {{ points[5] }}
Result is {{ points[2]+points[4] }}
Result is {{ points[2+1] }}
Result is {{ points[2*2] }}

Tuesday, 5 August 2014

Patterns and nuts!

Ask yourself this - Why do they always put a nut in a place where the spanner cannot reach it? - when you find the problem and the design pattern not matching.

All problems could be the same. It is only the context, the domain, the applicability, the robustness that the solution must be subject to, the experience and maturity of the solution provider that make problems unique and different.

A psycho's reactions can be easily simulated in a child and for those to whom the child is not visible, from afar or through heresy or by reading about it, both will seem the same. It is this knowledge that is important to make decisions and not whether the similarity of actions with a psycho makes a child a psycho nor whether the psycho is a child.

This knowledge, the ability to dwell deep to the real core of a problem, is what is necessary to know where designs emerge and which design patterns to decide on.

Tuesday, 15 July 2014

Blogger post from ASP.Net

Sample post! It looks like setting a draft post to false on the AtomEntry object does not work or it is simply a matter of providing the postId alongwith the blogId and not setting the URL to default feeds.

Below is the code: (you can use NUGet to install the Google API into your VS project)

using System;
using Google.GData.Client;
using System.Web.UI;

namespace BloggerPost
{
    public partial class _Default : Page
    {
        string blogId = ""; // This id will be part of the query string in your browser address bar when you access your blog
        string username;
        string password;
        private void PostOrUpdateBlogPost(string yourBlogId,bool isUpdate)
        {
            if (yourBlogId != null)
            {
                var service = new Google.GData.Client.Service("","Application Name");
                service.Credentials = new GDataCredentials(username, password);
                AtomEntry newPost = null;
                if (isUpdate)
                {
                    try
                    {
                        // need to correct the URL here
                        newPost = service.Get(yourBlogId);
                        newPost.Categories.Clear();
                        // Setting the isDraft property requires the above URL to contain the postId (need to confirm test this).
                        if (newPost.IsDraft) newPost.IsDraft = false;
                    }
                    catch (Exception ex)
                    {

                    }
                }
                else
                {
                    newPost = new AtomEntry();
                    newPost.Title.Text = "Blogger post from ASP.Net";
                    newPost.Content = new AtomContent();
                    newPost.Content.Content = "Sample post! It looks like setting a draft post to false on the AtomEntry object does not work or it is simply a matter of providing the postId alongwith the blogId and not setting the URL to default feeds.";
                    newPost.Content.Type = "html";
                }
             
                try
                {
                    if (!isUpdate)
                    {
                        Uri blogPostUri = new Uri("http://www.blogger.com/feeds/" + yourBlogId + "/posts/default");
                        newPost = service.Insert(blogPostUri, newPost);
                    }
                    else
                    {
                        newPost = newPost.Update();
                    }
                }
                catch (Exception ex)
                {              
                }
            }
        }
 
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                PostOrUpdateBlogPost(blogId,false); // the boolean is to specify if it is a new post or an update.
            }
        }
 
    }
}

Publishing a post using the Google API for Blogger!

It is not as easy as many have posted on the web! Many posts indicate that all you need to do

is send in your credentials to the service object. Not as simple as that !

Blogger API Post


This post was created with the Blogger API v3

Tuesday, 17 June 2014

Two singularly complex problems - Arrays and Lists

The delightful aspect of programming in C# is the large number of possibilities, to resolve a problem, available to a programmer in the form of different forms of implementations across versions of the underlying technology and framework.

It is delightful because two different programmers may provide a solution to the same problem, without differing in technique, because the implementation of the same language feature across the different versions of the C# language compiler are different.

It can be torrid, though, if you do not enjoy the intricacies of working with different types in the CLR and/or the underlying unmanaged types of the Windows platform.

1. Unmanaged array - the 'mysterious' object[*]

The Microsoft.Office.Interop,Excel Chart object presents a challenge in the way it exposes the Chart's series collection's data values.

For instance, if you want to read the Chart's Source Data range/Data Table, the problem is in the way the series collection exposes each series' data values. Being a System.ComObject, the series.Values (that represent each Chart Series values) returns an unmanaged array !! What is so surprising, you may ask?

The surprise is that you may convert it to an object array but may inadvertently leave out testing it as it will compile ok. At runtime, though, an error that an object of type [,] cannot be converted to an object of type [] will be thrown!

The exasperating aspect of this error has to be experienced to really appreciate the nature of the error !!

The reason it is exasperating is because you may try creating an Array with CreateInstance and while it should work, at a glance,

var array = System.Array.CreateInstance(
                            typeof(object),
                            new int[] { totalColumns },
                            new int[] { totalRows });
array = series.Values;

it does not !

The solution is to iterate through the series.Values as below:

// --- 1. Get ChartObjects in worksheet
//-- 2. iterate through the chart object's series collection

foreach (object seriesValue in series.Values as System.Array)
{
double d = (double)seriesValue;
list.Add(d);
}

The trick is to convert the unmanaged array values into an array while iterating through it !

Best Practice
3. If you are using a System.ComObject in a for... or foreach... loop make sure to release the COM object with Marshal.ReleaseComObject in the System.Runtime.Interopservices namespace in the finally block of a try...catch as below:

foreach (..... ComObject in ...){
try{
....
}
catch{}
finally{
if (object!=null)
Marshal.ReleaseComObject.(...);
}
}

Remember, you cannot set a ComObject used in a loop to null ! A runtime exception will be thrown if you attempt to do so.


2. Compare two Lists or Arrays

The option to obtain the iterated value into an array or a list is as per your requirement.

In both the cases, you may want to work with both the array or the list. 

Below are two techniques to compare, using, first, the TrueForAll Linq method (make sure to add the System.Linq namespace) as below.

                            var list = new System.Collections.Generic.List();
                            var list1 = new System.Collections.Generic.List();

                                            if (list.TrueForAll(list1.Contains) && list1.TrueForAll(list.Contains))
                                            // --

Or, convert the array into a List and use the System.Array's SequenceEqual check for an array,

object[] rangeValueArray = (from item in list select item as object).ToArray();
object[] seriesValueArray = (from item in list1 select item as object).ToArray();

if (rangeValueArray.SequenceEqual(seriesValueArray))
// --
else if (!rangeValueArray.SequenceEqual(seriesValueArray))
// --

This method helps check if the elements are equal plus in sequence !