1

I'm writing code that will execute a series of test steps, these test steps will align to test steps manually captured in a test case, here is an example:

enter image description here

The above screenshot shows 3 steps for a sample test case (This is viewed using Microsoft Test Manager).

Please also keep in mind this is a primitive example, simplified for this question, in reality it's not uncommon to have 50 test steps and vastly more complicated scenarios, also I've omitted cleanup and entry code in the below function.

Now the code that runs this looks something like this: (Pay attention to the try/catch mechanism which allows the test to fail on a particular step) :

[TestMethod] public void LinksPageOpensFromClick() { int step = 0; try { step++; // Code to Open the page } catch (Exception ex ) { Assert.Fail(AppManager.RaiseError(step, "Open the page", ex)); } try { step++; // Code to Click links button } catch (Exception ex) { Assert.Fail(AppManager.RaiseError(step, "Click links button", ex)); } try { step++; // Code to Assert links page opened } catch (Exception ex) { Assert.Fail(AppManager.RaiseError(step, "Assert links page opened ", ex)); } } 

First observation is, I used to just hard code in the value of step like this:

Assert.Fail(AppManager.RaiseError(3, "Assert links page opened ", ex)); 

But this means that should the test change later, and test steps added or reordered, it means manually changing a vast number of steps.

Having steps as an incremented variable too isn't ideal, firstly it's not exactly elegant, and it's too error prone if you forget to increment the step. In addition you can't pattern scan the code and see what step you're on without adding additional comments.

What I'm really looking for is a solution like this:

[StepDesc="Assert links page opened"] Step { // Code to exec } Error (Exception ex) { Assert.Fail(AppManager.RaiseError(Step.Count, Step.Desc, ex)); } 

Failing that, a cleaner way to increment step count or make it more dynamic without having to manually increment it.

Also if C# cannot handle this, perhaps I could put all my front facing test cases in another project which might not be C# but is MSIL compliant?

4
  • this might be a better question for code review. that said, you could store a Dictionary<int,string> with # of step to error text Commented Jan 26, 2015 at 13:17
  • you could also create methods for each step instead of having a single gigantic method. Commented Jan 26, 2015 at 13:18
  • DLeh, nice suggestion but then you would still need to throw that error with a manual index position in the catch block. Commented Jan 26, 2015 at 13:19
  • Adding onto the suggestion of creating separate methods; you could apply AOP and decorate them with aspects, which could incorporate your try-catch logic and tidy up your code even further. Have a look at PostSharp. Commented Jan 26, 2015 at 13:25

2 Answers 2

4

This obviously needs to go in a loop, i.e. something like:

class Step { public string Name { get; set; } public Action Action { get; set; } } var steps = new [] { new Step() { Name = "Open the page", Action = OpenThePageStep }, new Step() { Name = "Click links button", Action = ClickLinksBtnStep }, ... }; ... var id = 0; // or the Step class itself should have an id? foreach (var step in steps) { try { id++; step.Action(); } catch (Exception ex) { Assert.Fail(AppManager.RaiseError(id, step.Name, ex)); } } 
Sign up to request clarification or add additional context in comments.

1 Comment

Looks like I'm bit late to the game; deleted my answer. +1
2

If the steps are manually implemented (and not e.g. autogenerated from a formal description, in which case Groo's solution that defines a Step class is indeed better), this is probably how I would do it, as it seems to be the simplest way, and at least if each single step's code is simple, I also find a more readable:

public class Stepper { private int StepNumber { get; set; } public void Step(string description, Action code) { StepNumber++; try { code(); } catch (Exception ex) { Assert.Fail(AppManager.RaiseError(StepNumber, description, ex)); } } } 

Then your test code would look like this:

var stepper = new Stepper(); stepper.Step("Open the page", () => { /* code to open the page */ }); stepper.Step("Click links button", () => { /* code to click links button */ }); // etc. 

One thing that may or may not be interesting for you is that you could fairly easily implement a way to create nested steps, e.g. something like

var stepper = new Stepper(); stepper.Step("Foo the bar", () => { /* ... */ }); using (var substep = stepper.SubStep("baz all the quuxs")) { substep.Step("baz the first quux", () => { /* ... */ }); substep.Step("baz the second quux", () => { /* ... */ }); } stepper.Step("cleanup", () => { /* ... */ }); 

1 Comment

This is actually the solution I've gone with - and I made one small adjustment -> in public void step added a [DebuggerStepThrough], this way I can f11 my way into the actual code without going through the step method :) Very nice work - and thank you.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.