Sunday, October 12, 2014

Compare arrays in powershell using Pester

Recently I had to create deployment scripts using powershell. At some point our team realised that we need some way to test behavior of our scripts. After googling and comparing different libraries we decided to go with pester. It fits our needs and is actively supported, plus it's really easy to integrate into CI server.

Let's take a look at very simple examples.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
Describe 'Pester demo' {
 Context 'Basic math' {   

  It 'Should add 2 numbers' {
   $sum = 2 + 7

   $sum | Should Be 9
  }

  It 'Should deduct 2 numbers' {
   $sum = 10 - 3

   $sum | Should Be 7
  }
 }
}

Nothing special, assertions work as pipeline functions. I personally like that library, it supports different kind of assertions, the only problem that I had is how to assert arrays equality.
Let's try to comapre two arrays.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Describe 'Compare arrays' {
 Context 'There are 2 arrays' {
  $array1 = 1, 2, 3
  $array2 = 1, 2, 3

  It 'Should be green' {
   $array1 | Should Be $array2
  }
 }
}

Output







Looks ok, let's break the test.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Describe 'Compare arrays' {
 Context 'There are 2 arrays' {
  $array1 = 1, 2, 4
  $array2 = 1, 2, 3

  It 'Should be green' {
   $array1 | Should Be $array2
  }
 }
}

Output



It's not really clear  what is really broken.
Let's see how we can improve it:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
Describe 'Compare arrays' {
 Context 'There are 2 arrays' {
  $array1 = 1, 2, 4
  $array2 = 1, 2, 3

  $arrayStr1 = $array1 -join ', '
  $arrayStr2 = $array2 -join ', '

  It 'Should be green' {
   $arrayStr1 | Should Be $arrayStr2
  }
 }
}

Output













Now it makes more sense.

Sunday, August 17, 2014

A public action method 'X' was not found on controller 'Y'

Recently I've met a very strange exception in my application. A public action method 'X' was not found on controller 'Y'. After googling for a while I found that it can be when your action is marked with HttpPost or HttpGet attribute, but http method of you request doesn't fit to it. In my case my method action was marked as HttpPost and I was pretty sure that I use POST method in my request. Then I used debugger and found that HttpContext.Request.HttpMethod is equals to "GET". It was really strange. It actually means that something changes my request. I went to Web.config and found something really interesting – UrlRewrite module and bunch of rules. My request was affected by one of them, that led to redirect, and because of redirect it changed original POST http method to GET.

Sunday, July 27, 2014

Build configurations cleanup

Currently I'm working on a big project where we have a lot of legacy code. The big problem was build configurations. There were around 8 or 10 different configurations, of cause DEBUG and RELEASE, but besides we had QA, Production, Integration and Staging. Problem is that we had also some garbage, some old configurations like Demo1, Demo2, Test and something else. Another problem is that some projects were configured as Any CPU other as x86. We had real mess in csproj and sln files.
To normalize everything I created small tool. Basically we need to do two things:

1. Remove all build configurations from csproj files and add there only those that we need.
2. Remove all build mappings from sln files and created them from scratch.

Let's talk about the first step. csproj-file is simple xml file. So what we need is just open xml file, remove some nodes and add another nodes. Here is the part of the code.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
private void CureProject(string projectPath, IEnumerable<string> buildConfigurations)
{
    var doc = XDocument.Load(projectPath);

    var ns = doc.Root.GetDefaultNamespace();

    var mainPropertyGroup =
        doc.Root.Elements()
            .Single(
                x =>
                    x.Name.LocalName == "PropertyGroup" &&
                    x.Elements().Any(sx => sx.Name.LocalName == "OutputType"));

    doc.Root.Elements()
        .Where(
            x =>
                x.Name.LocalName == "PropertyGroup" && x.HasAttributes &&
                x.Attributes().Any(atr => atr.Name.LocalName == "Condition"))
        .ToList()
        .ForEach(x => x.Remove());

    var isWeb = doc.Root.ToString().Contains("WebProjectProperties");

    foreach (var buildConfiguration in buildConfigurations)
    {
        if (buildConfiguration == "Debug" || buildConfiguration == "Integration")
        {
            mainPropertyGroup.AddAfterSelf(CreateDebugBasedBuildConfiguration(ns, buildConfiguration, isWeb));
        }
        else
        {
            mainPropertyGroup.AddAfterSelf(CreateReleaseBasedBuildConfiguration(ns, buildConfiguration, isWeb));
        }
    }

    doc.Save(projectPath);
}

Let's discuss what we do here. Each csproj file contains several PropertyGroup nodes. One of them is main one or a default one. It has no conditions. Here's an example:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProjectGuid>{449C9CCD-35FC-4D38-932E-6243C4517090}</ProjectGuid>
    <OutputType>Library</OutputType>
    <AppDesignerFolder>Properties</AppDesignerFolder>
    <RootNamespace>SolutionNormalizer</RootNamespace>
    <AssemblyName>SolutionNormalizer</AssemblyName>
    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
    <FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <DebugSymbols>true</DebugSymbols>
    <DebugType>full</DebugType>
    <Optimize>false</Optimize>
    <OutputPath>bin\Debug\</OutputPath>
    <DefineConstants>DEBUG;TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
</PropertyGroup>

So we have 2 nodes here. First one is what I call main one, witout any conditions. It has improtant info like project type or target framework. The second node has a condition. And thta is very important. We actualy take main one and then, if codition is satisfied, we take additional node. Then we add or overwrite some properties. It mean tha if configuration is Debug and target platform is AnyCPU then we take additonal properties from tha section as DebugType or OutputPath. So we want to keep a main node and remove the rest. That is what does our code in lines 14-20. Then we need to if thta is a web project. We will need it later. So don't care about it right now. Thaen we have a loop through the collection of build configurations that we want to add. Inside fe have a condition.

if (buildConfiguration == "Debug" || buildConfiguration == "Integration")

It's a bit haky...what I actually want here is to spleet all build configurations into 2 categories: based on debug configuration and based on release configuration. The difference is not so big, we just set some properties a bit differently. We set differently DebugSymbols and Optimization. We will take a look mode deeply. Let's just take a look how we create debug based nodes and release based nodes:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
private XNode CreateDebugBasedBuildConfiguration(XNamespace ns, string buildConfiguration, bool isWeb)
{
    var result = new XElement(ns + "PropertyGroup",
        new XAttribute("Condition",
            string.Format(" '$(Configuration)|$(Platform)' == '{0}|AnyCPU' ", buildConfiguration)),
        new XElement(ns + "DebugSymbols", "true"),
        new XElement(ns + "DebugType", "full"),
        new XElement(ns + "Optimize", "false"),
        new XElement(ns + "OutputPath", isWeb ? @"bin\" : string.Format("bin\\{0}\\", buildConfiguration)),
        new XElement(ns + "DefineConstants", "DEBUG;TRACE"),
        new XElement(ns + "ErrorReport", "prompt"),
        new XElement(ns + "WarningLevel", "4")
        );

    return result;
}

private XNode CreateReleaseBasedBuildConfiguration(XNamespace ns, string buildConfiguration, bool isWeb)
{
    var result = new XElement(ns + "PropertyGroup",
        new XAttribute("Condition",
            string.Format(" '$(Configuration)|$(Platform)' == '{0}|AnyCPU' ", buildConfiguration)),
        new XElement(ns + "DebugType", "pdbonly"),
        new XElement(ns + "Optimize", "true"),
        new XElement(ns + "OutputPath", isWeb ? @"bin\" : string.Format("bin\\{0}\\", buildConfiguration)),
        new XElement(ns + "DefineConstants", "TRACE"),
        new XElement(ns + "ErrorReport", "prompt"),
        new XElement(ns + "WarningLevel", "4")
        );

    return result;

The difference is not so big as you can see. As I wrote above we set a bit differently DebugType and Optimize properties. Now we have to discuss why do we need that isWeb parameter. Difference is that noraly build path cotains buildconfiguration name, like bin\Debug or bin\Release. But it's not relevant for web applications. Important thing is the xml namespace that we retriev from csproj file and then use to create the nodes. Wthout that namespace output file will look differetly, but we want to keep everything clean and keep everything as like it was generated by visual studio.

Now we should take a look what should we do with sln files. Here is the code that does all magic.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
private void CureSolution(string solutionPath, IEnumerable<Tuple<string, string>> mappings)
{
    var solution = SolutionParser.Parse(solutionPath);

    var vsFolderGuid = new Guid("2150e333-8fdc-42a3-9474-1a3956d46de8");

    var projects = solution.Projects.Where(p => p.TypeGuid != vsFolderGuid).ToList();

    var projectGuids = projects.Select(p => p.Guid).ToList();

    var slnContent = File.ReadAllText(solutionPath);

    var projectConfigurationRegex =
            new Regex(
                @"GlobalSection\(ProjectConfigurationPlatforms\) = postSolution.*?EndGlobalSection",
                RegexOptions.Singleline);            

    var newContent = CreateProjectConfigurationPlatforms(projectGuids, mappings);

    var result = projectConfigurationRegex.Replace(slnContent, newContent);

    newContent = CreateSolutionConfigurationPlatforms(mappings);

    var solutionConfigurationRegex =
            new Regex(
                @"GlobalSection\(SolutionConfigurationPlatforms\) = preSolution.*?EndGlobalSection",
                RegexOptions.Singleline);

    result = solutionConfigurationRegex.Replace(result, newContent);

    File.WriteAllText(solutionPath, result);
}

private string CreateSolutionConfigurationPlatforms(IEnumerable<Tuple<string, string>> mappings)
{
    var sb = new StringBuilder();

    sb.Append("GlobalSection(SolutionConfigurationPlatforms) = preSolution\r\n");

    foreach (var mapping in mappings)
    {
        sb.AppendFormat("\t\t{0}|Any CPU = {1}|Any CPU\r\n", mapping.Item1, mapping.Item1);
    }

    sb.Append("\tEndGlobalSection");

    return sb.ToString();
}

private string CreateProjectConfigurationPlatforms(IEnumerable<Guid> projectGuids,
    IEnumerable<Tuple<string, string>> mappings)
{
    var sb = new StringBuilder();

    sb.Append("GlobalSection(ProjectConfigurationPlatforms) = postSolution\r\n");

    foreach (var projectGuid in projectGuids)
    {
        foreach (var mapping in mappings)
        {
            var projectFormatedGuid = projectGuid.ToString("B");

            sb.AppendFormat("\t\t{0}.{1}|Any CPU.ActiveCfg = {2}|Any CPU\r\n",
                projectFormatedGuid.ToUpper(), mapping.Item1, mapping.Item2);
            sb.AppendFormat("\t\t{0}.{1}|Any CPU.Build.0 = {2}|Any CPU\r\n", projectFormatedGuid.ToUpper(),
                mapping.Item1, mapping.Item2);
        }
    }

    sb.Append("\tEndGlobalSection");

    return sb.ToString();
}

It's definitely not the best code you've ever seen, it's more like a working prototype. Later I'm going to ckean it up and publish as a console tool. But it works pretty fine and does what I need.
We should star from short intro to what sln file is. It's not an xml file. It's more or less plain text devided in couple sections. At the begining of that file there is a list of all projects linked in that solution. Bellow there are some global sections. We need only two of them. One fefines a list of all available build configurations, another one defines how to map those configurations to configurations that are defined in csproj files.

Here is an example how looks definition of available configurations in solution file:

1
2
3
4
5
GlobalSection(SolutionConfigurationPlatforms) = preSolution
 Debug|Any CPU = Debug|Any CPU
 Release|Any CPU = Release|Any CPU
 QA|Any CPU = QA|Any CPU
EndGlobalSection

It's really straight forward approach. Nothing interesting. It means tha we have 3 configurations available in our solution.
Second scectoins maps solution build configurations to project build configurations. We can do it as one to one mappings or as many to many. Here is an example how we can map one to one.

1
2
3
4
5
6
7
8
GlobalSection(ProjectConfigurationPlatforms) = postSolution
 {449C9CCD-35FC-4D38-932E-6243C4517090}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 {449C9CCD-35FC-4D38-932E-6243C4517090}.Debug|Any CPU.Build.0 = Debug|Any CPU
 {449C9CCD-35FC-4D38-932E-6243C4517090}.Release|Any CPU.ActiveCfg = Release|Any CPU
 {449C9CCD-35FC-4D38-932E-6243C4517090}.Release|Any CPU.Build.0 = Release|Any CPU
 {449C9CCD-35FC-4D38-932E-6243C4517090}.QA|Any CPU.ActiveCfg = QA|Any CPU
 {449C9CCD-35FC-4D38-932E-6243C4517090}.QA|Any CPU.Build.0 = QA|Any CPU
EndGlobalSection

It means that we have 3 build configurations defined on solution level and 3 configurations defined on project level. It menas that project file should contains 3 conditional PropertyGroup nodes.
Bellow is an example how we can map many to many.


1
2
3
4
5
6
7
8
GlobalSection(ProjectConfigurationPlatforms) = postSolution
 {449C9CCD-35FC-4D38-932E-6243C4517090}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 {449C9CCD-35FC-4D38-932E-6243C4517090}.Debug|Any CPU.Build.0 = Debug|Any CPU
 {449C9CCD-35FC-4D38-932E-6243C4517090}.Release|Any CPU.ActiveCfg = Release|Any CPU
 {449C9CCD-35FC-4D38-932E-6243C4517090}.Release|Any CPU.Build.0 = Release|Any CPU
 {449C9CCD-35FC-4D38-932E-6243C4517090}.QA|Any CPU.ActiveCfg = Release|Any CPU
 {449C9CCD-35FC-4D38-932E-6243C4517090}.QA|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection

It means that we have only 2 configurations on project level: debug and release. It means that we have 2 conditional PropertyGroup nodes in csproj file. But we still have 3 build configurations on solution level. We just define that in case of QA it should treat it as it were Release configuation.
You might ask why do I need all that stuff. So in my case there are about 20 sln files and 296 csproj files.And everytime it's diferrent...some solution have more build configurations some less, sometimes it's mpped one to one, sometimes many to many, we just want to keep to same strategy everywhere. Another reason that latter we want to have only Debug and Release build configuraions instead of 8 that we have now. With code that we have seen above it's realy easy. I forget to show what mappings actualy are. So bellow is usage of CureSolution method.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
var mappings = new[]
    {
        Tuple.Create("Debug", "Debug"),
        Tuple.Create("Integration", "Debug"),
        Tuple.Create("Release", "Release"),
        Tuple.Create("QA", "Release"),
        Tuple.Create("Production", "Release"),
        Tuple.Create("Staging", "Release")
    };            

foreach (var slnPath in solutions)
{
    CureSolution(slnPath, mappings);
}

In this particular case we map Debug and Integration as debug on project level, and the rest as release configurations.

Last things. I forgot to mention how I parse solution file and get projecs guid's. To do that I use nuget package Onion.SolutionParser. Anothe things is variable vsFolderGuid. Thing is that if solution contains some folder, those folder are treated also like projects with some special project type, we can filter them out by type guid. We have othing to do with solution folders when we do something with build configurations.

Thursday, July 3, 2014

Ternary operation powershell

I googled for ternary operation in powershell and found basically nothing, at least nothing good. It's seems like operations is not supported out of the box. There is a suggestion how it can be done using hash table.
Something like this:


$x = @{$true=10; $false=5}[$y % 2 -eq 0]

We just create a hash table with 2 boolean keys and then in accessor block evaluate condition.
In order to make it clear it might be simplified like that:


$key = $y % 2 -eq 0
$values = @{$true=10; $false=5}
$x = $values[$key]

Works fine but in my opinion not easy to read. It's always possible to invent a wheel. To add some custome function, I created that one:


function when {
 Param(
  [bool]$expression = $(throw "Boolean expression is required"),
  $then = $(throw "-then value is required"),
  $otherwise = $(throw "-otherwise value is required")
 )
 
 if ($expression) {
  return $then
 }
 
 return $otherwise
}

Here is an example of usage


$x = when ($y % 2 -eq 0) -then 10 -otherwise 5

I think it quite easy to read, but there is one thing that I really don't want to do, to add this function to every place where I need. In case you have many scripts and some script with the common stuff like Common.ps1, then maybe it's ok, since Common.ps1 is already linked everywhere. But it would be really nice to have something simple. And there is an option. Thing is that keyword return in powershell is not so required. Both function bellow return the same value:


function f1() {
 return 10
}

function f2() {
 10
}

Now let's try to think about obvious way how to deal with conditional logic. There is IF statement. So we can set a variable like that:

if ($y % 2 -eq 0) {
 $x = 10
} else {
 $x = 5
}

Let's improve it:


$x = if ($true) {
 return 10
} else {
 return 5
}

And the last improvement:


$x = if ($true) { 10 } else { 5 }

quite simple and no additional function is required. And it supports evaluation of some complex functions:


$z = if ($true) { someFunction $y $x } else { otherFunction $y $x }

Sunday, November 10, 2013

Get rid of switch statement

Yesterday I saw a piece of a legacy code that was written around 4 years ago. It is a plain old generic http handler that implements IHttpHandler interface. This handler is used for a simple data exchange between client code and a server through AJAX calls. This handler simply takes parameter sent from the client side and process them using some complex logic and switch statement. Let's take a look to a simple version of such handler. Let's imagine that our handler do some math operations:

public class Calculator : IHttpHandler
{

    public void ProcessRequest(HttpContext context)
    {
        context.Response.ContentType = "text/plain";

        var operation = context.Request.Params["operation"];

        var a = int.Parse(context.Request.Params["a"]);
        var b = int.Parse(context.Request.Params["b"]);

        var result = 0;

        switch (operation)
        {
            case "add":
                result = a + b;
                break;
            case "subtract":
                result = a - b;
                break;
            case "multiply":
                result = a * b;
                break;
            default:
                throw new NotSupportedException(string.Format("Operation {0} is not supported", operation));
        }

        context.Response.Write(result);
    }

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
}

It's pretty straight forward. The problem comes when we need to support a lot of operations. Then our switch statement becomes really big and heavy. How can we fix it!? Probably we need to do some refactoring. But first I'd extract all that logic to a separate class, so that our handler will take params pass them to the service and write a response back to a client. Another good reason to have a separate service is an ability to test our logic. So let's create a math service and call it from the handler.


public class MathService
{
    public int Perform(string operation, int a, int b)
    {
        switch (operation)
        {
            case "add":
                return Add(a, b);
            case "subtract":
                return Subtract(a, b);
            case "multiply":
                return Multiply(a, b);
            default:
                throw new NotSupportedException(string.Format("Operation {0} is not supported", operation));
        }
    }

    private int Add(int a, int b)
    {
        return a + b;
    }

    private int Subtract(int a, int b)
    {
        return a - b;
    }

    private static int Multiply(int a, int b)
    {
        return a * b;
    }
}

Now our handler looks like this:

public void ProcessRequest(HttpContext context)
{
    context.Response.ContentType = "text/plain";

    var operation = context.Request.Params["operation"];

    var a = int.Parse(context.Request.Params["a"]);
    var b = int.Parse(context.Request.Params["b"]);

    var mathService = new MathService();

    var result = mathService.Perform(operation, a, b);

    context.Response.Write(result);
}

Now our switch is inside MathService and it would be really cool to refactor it, but first we need to cover existing logic with unit tests in order to be sure that everything works as before after refactoring.
Let's write simple tests:


[TestFixture]
public class calculator_tests
{
    [TestCase("add", 3, 5, 8)]
    [TestCase("subtract", 3, 5, -2)]
    [TestCase("multiply", 3, 5, 15)]
    public void should_calculate_ints(string operation, int a, int b, int expectedResult)
    {
        var calculator = new MathService();

        int result = calculator.Perform(operation, a, b);

        Assert.That(result, Is.EqualTo(expectedResult));
    }
}

We have three operations in our service and three test cases. Now we are good to go.
What we can do here it's try to implement a design pattern called Match or Matcher. The point is that each our operation is a separate class and each class that presents math operation has a method called IsMatch so that we can peak up a right one from the list of all available operations. Let's switch to code.

public abstract class MathOperation
{
    private readonly string _operationName;

    public MathOperation(string operationName)
    {
        _operationName = operationName;
    }

    public bool IsMatch(string operationName)
    {
        return _operationName == operationName;
    }

    public abstract int Perform(int a, int b);
}

public class Add : MathOperation
{
    public Add() : base("add")
    {
    }

    public override int Perform(int a, int b)
    {
        return a + b;
    }
}

public class Subtract :  MathOperation
{
    public Subtract() : base("subtract")
    {
    }

    public override int Perform(int a, int b)
    {
        return a - b;
    }
}

public class Multiply : MathOperation
{
    public Multiply() : base("multiply")
    {
    }

    public override int Perform(int a, int b)
    {
        return a * b;
    }
}

We have a base abstract class MathOperation that has two methods: IsMatch and abstract method Perform. IsMatch checks if operations is appropriate, in our case we check using operation name, of cause in real situation we might have more complex logic. Now let's change our MathService.


public class MathService
{
    public int Perform(string operation, int a, int b)
    {
        var operationsList = new MathOperation[]
            {
                new Add(),
                new Subtract(),
                new Multiply()
            };

        var operationHandler = operationsList.Single(o => o.IsMatch(operation));

        return operationHandler.Perform(a, b);
    }
}

We defined a collection of the operations and using LINQ we take a single one that matches by operation name. Now let's run our test and we see that everything is OK. The good thing about it that we easily can add new operations and we can test each operation separately.

Thursday, October 31, 2013

Make your tests human readable.

We started to use selenium tests almost 2 years ago and since that moment we changed our approach twice. At the very beginning we had only one person involved in that process, we had a lot of "copy/paste", because all tests are more like a complex scenarios with some prerequisites and dependencies. So there were obviously a need to refactor everything and make code more clear and maintainable. I definitely should mention that each test had over 60 lines of code and two test usually had around 80% of duplicated code that means we had a lot of  "copy/paste". The first and most obvious way to fix all these shit was to create a base class and put there all common logic. Each logical block in a separate method. So that we got rid of global "copy/paste" between test and achieved the reusable parts.

Life became easier but there still were a room for improvements. We wanted to have tests writen in a such way that even a not technical person could read it. We wanted some kind of a DSL. And then we tried a SpecFlow. It looked very cool and we were encourage to try it. But it turned out to be that SpecFlow did not feet our needs due to a couple things:
  • It's built over regular expressions to match scenario and real code, but has no intellisense and no tools that prevent misspelling
  • In some cases we have really complex setup and it's really hard, I'd rather say impossible, to describe it in SpecFlow way.
We decided to go our own way and create our own DSL. Actually we created following:
  • Base class with protected methods like: Login, Logout, GoToPage, OpenXxxWindow etc.
  • Helper classes to work with cookies, with Selenium Web driver etc.
It became better. Here is a small example of how our code looked at that period of time:

[TestFixture]
public class customer_should_be_able_to_order_a_book : BaseTest
{
 [Test]
 public void customer_should_approve_delivery_after_successfull_shippment()
 {
  LoginAsCustomer();
  {
   OpenBookStoreWebPage();

   FindBook();

   AddToTheBasket();

   CheckOutTheOrder();
  }

  LoginAsManager();
  {
   GoToOrders();

   FindAnOrder();

   ConfirmShippmnet();
  }

  LoginAsCustomer();
  {
   GoToMyOrders();

   ApproveDelivery();
  }
 }
}

Actually not bad...but there are some issues which such approach does not solve. In order to make it clear I warn that curly braces after LogincAsCustomer does nothing except group methods bellow in one logical context. Login method has two implementations: LoginsAsCustomer and LoginAsManager. Let's imaging the situation when we want to write a scenario with two customers, obviously we will create another method with ugly name LoginAsCustomer2 or LoginAsSecondCustomer and so on in case we need three or four customers simultaneously. Or another example...now we have step ApproveDelivery for customer, but we might want to have an ability to approve delivery on behalf of a customer, it means that our manager will need another method with slightly different name ApproveDeliveryOnBehalf or something very similar. But what we really wanted it some context specific approach. Ability to use the same method login that is aware about which credentials to use.
I'm totally into DI and loosely coupled code, I want to have small and well described steps for my tests. Let's look how should look simple step, as an example I will show Login step.

public class Login : BaseStep, IExecutableStep
{
    public UserCredentials _userCredentials;

    public Login(UserCredentials userCredentials)
    {
        _userCredentials = userCredentials;
    }

    public void Execute()
    {
        //fake implementation
        Logger.Log("Login: {0}", _userCredentials.Login);
            
        Logger.Log("Password: {0}", _userCredentials.Password);
    }
}

For demo purpose this code doesn't interact with database or some other services, it only logs in console user credentials. It has Execute method from IExecutabeStep, each step in our scenario should be executed :) so all steps should implement this scenario. And it also has a BaseStep as ancestor we will look later at BaseStep more deeply. Login step should know a credentials to use. It means that our login step has a dependency and we need a way to solve it some how. And the most interesting thing that we can resolve it differently according to execution context. And this is the time to show what is execution context.

public interface IExecutionContext
{
 void AddContextBindings(IKernel kernel);

 void RemoveContextBindings(IKernel kernel);
}

My implementation is based on Ninject, it's open source IoC framework. Those who don't know what is Binding probably should get famiilar with Ninject or some other IoC container. Actually it's not so complicated. IKernel it's an interface that has very useful method Get which accept a type. Let's say we want to create an instance of Login step, then we will call

kernel.Get<Login>();

very simple, the thing is that by itself Login type is a public class and could be easily instantiated, but there is one issue. We have a dependency on UserCredentials and we need to know where to get this credentials. Here comes another method of kernel, it's method Bind. Most likely you would do something like this:

kernel.Bind<ISomeInterface>().To<SomeImplementation>();

Here we say that every time we want instance of ISomeInterface we should create an instance of SomeImplementation which should be obviously derived from ISomeInterface. In our case we want to have some user credential aware context, just like this one.

public class UserAwareContext : IExecutionContext
{
    private readonly UserCredentials _userCredentials;

    public UserAwareContext(UserCredentials userCredentials)
    {
        _userCredentials = userCredentials;
    }

    public void AddContextBindings(IKernel kernel)
    {
        kernel.Bind<UserCredentials>().ToConstant(_userCredentials);
    }

    public void RemoveContextBindings(IKernel kernel)
    {
        kernel.Unbind<UserCredentials>();
    }
}

Here we say that we want to resolve UserCredential by some specific object with some specific login and password. We can create two or more such contexts each with unique credentials, one for customer another for manager and so on, let take a look how to do it:

public class Users
{
    public static UserAwareContext Customer()
    {
        return new UserAwareContext(new UserCredentials
            {
                Login = "john",
                Password = "orange"
            });
    }

    public static UserAwareContext Manager()
    {
        return new UserAwareContext(new UserCredentials
            {
                Login = "manager",
                Password = "cherry"
            });
    }
}

It's a factory that knows how to create a context. So I can use Users.Customer(); and it will return we a customer context or I can  use Users.Manager(); and it will return me a manager context.
Now it's time to get everything together, our code will look like:

var customer = Users.Customer();

As(customer).Execute(() =>
{
    Do<Login>();
}

Let's talk about As and Do methods. As creates execution scope, it accepts IExecutionContext as parameter, a collection of IExecutionContext if to be more precised. And register all dependencies using AddContextBindings method. Then we call method Do which resolves step instance using all bindings declared in As method and then call Execute method of that step. Before to leave execution scope we need to remove all bindings that were declared at the beginning, at this point we need a method RemoveContextBindings of the interface IExecutionContext.

I almost forgot about BaseStep, this is how it looks.


public class BaseStep
{
    [Inject]
    public Logger Logger { get; set; }
}

Logger is marked with Inject attribute, it's a ninject attribute, that allow to mark a public property as a dependency that has to be resolved.

Source code and another examples are available on the bitbucket.
Later I'm going to show how to use it together with Selenium WebDriver, because initially this approach was designed to maintain complex scenarios above selenium.

Source code 

Thursday, October 17, 2013

Angular JS. "No image" directive

Hi everyone. I've been playing for 2 months with Angular JS and going to post a couple articles about it.
I was really impressed by a unique feature of angular js that allows to create custom tags and custom attributes using angular directives.

In our prototype we had a situation where we need to show some product details including product image.
Actually there are 3 valid cases for product image in our application:
  • we don't have an image url
  • we have a valid image url
  • we have broken image url (server errors like 404 or 503)
Let's start with the simple solution and then will improve it.
So if we have a url for a product lets show and image with that url, if we don't have an image let's use some default image like:

Our markup will be something like this:

<img ng-show="product.imageUrl" ng-src="{{product.imageUrl}}" />
<img ng-show="!product.imageUrl" src="/demo/img/no_image_small.png" />

It's very important to use ng-src directive instead of plain old src attribute. Why ?!...actually because it takes some time to instantiate and wire up all angular stuff, it's pretty fast but anyway browser will start loading an image using "product.image" like an url, before angular will evaluate this statement.
Let's handle now the situation when url is broken. It's very simple. There is an event called onerror let's add this handler to the first image tag. And let's define a handler for such event.

<img ng-show="product.imageUrl" ng-src="{{product.imageUrl}}" onerror="setDefaultImage(this)" />
<img ng-show="!product.imageUrl" src="/demo/img/no_image_small.png" />

Javascript handler:

function setDefaultImage(image) {
    image.src = "/demo/img/no_image_small.png";
}

Everything looks simple but:
  • It's hard to reuse: we will need to copy everything all the time
  • It's complicated and ugly
  • We introduced a global function
  • It's not the Angular JS way
Let's create a directive that will handle everything we need:

app.directive('noImage', function () {

    var setDefaultImage = function (el) {
        el.attr('src', "/demo/img/no_image_small.png");
    };

    return {
        restrict: 'A',
        link: function (scope, el, attr) {
            scope.$watch(function() {
                return attr.ngSrc;
            }, function () {
                var src = attr.ngSrc;

                if (!src) {
                    setDefaultImage(el);
                }
            });

            el.bind('error', function() { setDefaultImage(el); });
        }
    };
});

Actually all magic is inside the link function. We watch ngSrc, it's an url that we set from the markup. If we don't have a url then we use default image. Bellow we attach new event handler to the element and if error event occurs we again assign default image. nsSrc here comes from attr variable, attr variable it's just a collection of all attributes assigned to the html element. You also might have noticed that we wrote restrict: 'A', it means that we are going to use this directive as an attribute over html element. Why do we use scope.$watch !? well let's image a situation when somebody dynamically changes image url, then we will need to reevaluate our url and again display real image or image placeholder.

Here goes example of usage:

<img no-image ng-src="{product.imageUrl}}" />

To make code more flexible and reusable, we should get rid of hard coded image url inside the directive.
Since Angular JS is built with DI in mind let use that approach. Let's create some settings provider and inject it inside the directive. So our code will look like this:


app.factory('settings', function() {
    return {
        noImageUrl: "/demo/img/no_image_small.png"
    };
});

app.directive('noImage', function (settings) {

    var setDefaultImage = function (el) {
        el.attr('src', settings.noImageUrl);
    };

    return {
        restrict: 'A',
        link: function (scope, el, attr) {
            scope.$watch(function() {
                return attr.ngSrc;
            }, function () {
                var src = attr.ngSrc;

                if (!src) {
                    setDefaultImage(el);
                }
            });

            el.bind('error', function() { setDefaultImage(el); });
        }
    };
});

Now in case we need such directive in other application we easily can include script to the application and define a factory that will return appropriate url.