Showing posts with label UnitTesting. Show all posts
Showing posts with label UnitTesting. Show all posts

Friday, 22 June 2012

ShouldThrowException<T> Helper

Many unit test frameworks provide an assert wrapper for an expected exception such as the following in NUnit:

Assert.Throws<T>( code here );

Some frameworks like MS Test don’t and rely on the attributes on the test itself, rather than a specific line of code e.g.

[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void GivenConstructorWhenNameIsEmptyThenArgumentExceptionThrown()
{
code
}

If like me you prefer the more targeted nature of the latter so you can use the following code in your unit test project:

public static void ShouldThrowException<T>(Action action) where T : Exception
{
try
{
action();
}
catch (T)
{
return;
}

Assert.Fail("Expected exception did not occur");
}

Here is an example of its usage:

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace TestHelperShouldThrowException.Tests
{
[TestClass]
public class PersonTests
{
[TestMethod]
public void GivenConstructorWhenNameIsFiveCharactersThenPersonIsCreated()
{
Person person = new Person("Tommy");
Assert.IsNotNull(person);
}

[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void GivenConstructorWhenNameIsEmptyThenArgumentExceptionThrown()
{
Person person = new Person("");
}

[TestMethod]
public void GivenConstructoWhenNameIsEmptyThenArgumentExceptionThrownUpdated()
{
Helper.ShouldThrowException<ArgumentException>(() => new Person(""););
}
}

class Person
{
public string Name { get; set; }

public Person(string name)
{
if (string.IsNullOrEmpty(name))
throw new ArgumentException("Invalid name value");

Name = name;
}
}
}

Source: https://github.com/stevenh77/ShouldThrowException

Sunday, 27 May 2012

Code Contracts

I started writing a blog post about Code Contracts that I believe will end up working its way into all future .NET software, particularly APIs.  Then I came across this excellent write up that I highly recommend:

http://devjourney.com/blog/code-contracts-part-1-introduction/

Code Contracts in action

using System;
using System.Diagnostics.Contracts;

namespace CodeContracts
{
public interface IRandomGenerator
{
int Next(int min, int max);
}

public class RandomGenerator : IRandomGenerator
{
private readonly Random _random = new Random();

public int Next(int min, int max)
{
return _random.Next(min, max);
}
}

public class Randomizer
{
private readonly IRandomGenerator _generator;

public Randomizer(IRandomGenerator generator)
{
_generator = generator;
}

public int GetRandomFromRangeContracted(int min, int max)
{
Contract.Requires<ArgumentOutOfRangeException>(
min < max,
"Min must be less than max"
);

Contract.Ensures(
Contract.Result<int>() >= min &&
Contract.Result<int>() <= max,
"Return value is out of range"
);

return _generator.Next(min, max);
}
}
}

The above code Post build

public class Randomizer
{
// Fields
private readonly IRandomGenerator _generator;

// Methods
public Randomizer(IRandomGenerator generator)
{
this._generator = generator;
}

public int GetRandomFromRangeContracted(int min, int max)
{
int Contract.Old(min);
int Contract.Old(max);
__ContractsRuntime.Requires<ArgumentOutOfRangeException>(min < max, "Min must be less than max", "min < max");
try
{
Contract.Old(min) = min;
}
catch (Exception exception1)
{
if (exception1 == null)
{
throw;
}
}
try
{
Contract.Old(max) = max;
}
catch (Exception exception2)
{
if (exception2 == null)
{
throw;
}
}
int CS$1$0000 = this._generator.Next(min, max);
int Contract.Result() = CS$1$0000;
__ContractsRuntime.Ensures((Contract.Result() >= Contract.Old(min)) && (Contract.Result() <= Contract.Old(max)), "Return value is out of range", "Contract.Result<int>() >= min && Contract.Result<int>() <= max");
return Contract.Result();
}
}


Unit tests with Moq and NUnit test cases

using System;
using Moq;
using NUnit.Framework;

namespace CodeContracts.Tests
{
[TestFixture]
public class Given_mocked_RandomGenerator
{
private Mock<IRandomGenerator> _randomMock;
private Randomizer _randomizer;

[SetUp]
public void Setup()
{
_randomMock = new Mock<IRandomGenerator>();
_randomizer = new Randomizer(_randomMock.Object);
}

[TestCase(1, 0)]
[TestCase(2, 1)]
[TestCase(100, 10)]
[TestCase(0, -1)]
[TestCase(-1, -2)]
[TestCase(-10, -100)]
public void When_min_is_greater_than_max_Then_should_throw_exception(int min, int max)
{
Assert.Catch<Exception>(() => _randomizer.GetRandomFromRangeContracted(min, max));
}

[TestCase(0, 0)]
[TestCase(1, 1)]
[TestCase(10000, 10000)]
[TestCase(-1, -1)]
[TestCase(-10000, -10000)]
public void When_min_is_equal_to_max_Then_should_throw_exception(int min, int max)
{
Assert.Catch<Exception>(() => _randomizer.GetRandomFromRangeContracted(min, max));
}

[TestCase(1, 2, 0)]
[TestCase(10, 100, 7)]
[TestCase(-100, -10, -107)]
public void When_return_value_is_less_than_min_Then_should_throw_exception(int min, int max, int expected)
{
_randomMock
.Setup(r => r.Next(min, max))
.Returns(expected);

Assert.Catch<Exception>(() => _randomizer.GetRandomFromRangeContracted(min, max));
}

[TestCase(10, 100, 102)]
public void When_return_value_is_more_than_max_Then_should_throw_exception(int min, int max, int expected)
{
_randomMock
.Setup(r => r.Next(min, max))
.Returns(expected);

Assert.Catch<Exception>(() => _randomizer.GetRandomFromRangeContracted(min, max));
}

[TestCase(0, 2, 1)]
[TestCase(10, 100, 50)]
[TestCase(-100, 10, 5)]
[TestCase(int.MinValue, int.MaxValue, 1)]
[TestCase(int.MinValue, int.MaxValue, 0)]
[TestCase(int.MinValue, int.MaxValue, -1)]
public void When_min_is_less_than_max_Then_should_equal_expected_result(int min, int max, int expected)
{
_randomMock
.Setup(r => r.Next(min, max))
.Returns(expected);

var actual = _randomizer.GetRandomFromRangeContracted(min, max);

Assert.AreEqual(expected, actual);
}

[TestCase(0, 2, 0)]
[TestCase(10, 100, 10)]
[TestCase(-100, 10, -100)]
[TestCase(int.MinValue, int.MaxValue, int.MinValue)]
public void When_min_is_less_than_max_and_result_equals_min_Then_should_equal_expected_result(int min, int max, int expected)
{
_randomMock
.Setup(r => r.Next(min, max))
.Returns(expected);

var actualResult = _randomizer.GetRandomFromRangeContracted(min, max);

Assert.AreEqual(expected, actualResult);
}

[TestCase(0, 2, 2)]
[TestCase(10, 100, 100)]
[TestCase(-100, 10, 10)]
[TestCase(int.MinValue, int.MaxValue, int.MaxValue)]
public void When_min_is_less_than_max_and_result_equals_max_Then_should_equal_expected_result(int min, int max, int expected)
{
_randomMock
.Setup(r => r.Next(min, max))
.Returns(expected);

var actualResult = _randomizer.GetRandomFromRangeContracted(min, max);

Assert.AreEqual(expected, actualResult);
}
}
}

Source


http://stevenhollidge.com/blog-source-code/CodeContracts.zip

Saturday, 5 May 2012

Silverlight ViewModel Tests

As everyone knows Microsoft didn’t exactly have test driven development as their main focus when creating Silverlight.

Nowadays whilst testing in Silverlight has greatly improved, with both Microsoft and the community providing better test options for Silverlight, the situation is still not as good as we are used to in the rest of the .NET world.  For example, it’s a real pain not being able to run NCrunch in Silverlight or use xUnit or NUnit for my tests (there is an NUnit for Silverlight project but it’s out of date at the moment).

I currently use Silverlight Unit Tests (part of the Silverlight Toolkit SDK), StatLight with TeamCity integration and AgUnit for ReSharper as the test runner within Visual Studio.

Here’s how it’s done:

image

Create a Silverlight Application which will be your main XAP file project.  The trick is that this will act as a shell containing purely your views and your app.xaml file.  You'll probably want to create it with an ASP.NET Web Server Host project.

Next up create a Silverlight Class Library that we’ll call our Presentation Layer.  This will contain all the “code” such as your commands, converters and view models, etc.

Now we can add a Silverlight class library to our solution that will contain our tests.

UI Prototype

image

Code to Interfaces

First up define the interface to your ViewModel based on our UI prototype.

namespace SilverlightValidation.Interfaces
{
public interface IUserViewModel : INotifyDataErrorInfo,
INotifyPropertyChanged,
IUserModel
{
bool IsChanged { get; }
ICommand OkCommand { get; set; }
ICommand CancelCommand { get; set; }
}

public interface IUserModel
{
string Username { get; set; }
string Email { get; set; }
string Password { get; set; }
DateTime? DateOfBirth { get; set; }
string Description { get; set; }
}

public interface ICloneable<T>
{
T Clone();
}
}

Fluent Assertions

Fluent Assertions

For our tests I use the Fluent Assertions library to help reduce code and make the tests easier to read.

Fluent Assertions on Codeplex:    http://fluentassertions.codeplex.com/

ShouldRaisePropertyChangeFor

A good example is the Event Monitoring provided by Fluent Assertions, which internally contains an assert check for the Username Property Changed event.
var subject = new UserViewModel();
subject.MonitorEvents();
subject.Username = "adminSH";
subject.ShouldRaisePropertyChangeFor(x => x.Username);

View Model Tests


Helper for tests                               https://gist.github.com/2624206

A helper class that acts as a factory for providing pre-built objects such as a default ViewModel.

Constructor tests                             https://gist.github.com/2624197

When using Dependency Injection we need to check the arguments in our constructor are valid.

Commands tests                              https://gist.github.com/2624192

Check the commands are executable and execute as required.  For example, the OK command which might normally save to the database could be using a database service which could be mocked out by the test to check it has been executed.

INotifyDataErrorInfo tests                 https://gist.github.com/2624201

Validation rules need to be adhered to so we’ll need to test data values pass, fail and boundary check our validation logic.

INotifyPropertyChanged tests           https://gist.github.com/2624203

Obviously we’re using data binding in our view so we need to make sure property change notification events are being fired as we update our properties. I love the Fluent Assertions library for this, it gives a very clean and read to easy syntax for the tests – great framework!


Test Runner Output in Visual Studio


image


TeamCity CI Server Output


With the StatLight tool added to the repo a simple build step can be added to TeamCity:

StatLight.exe -d="SilverlightValidation\SilverlightValidation.Tests\bin\Release\SilverlightValidation.Tests.dll" –teamcity


image


StatLight Output


If you want to manually run StatLight outside of the Visual Studio process:


image


Browser Test Runner


image


Screenshot of working version


image


This online demo is here:  http://stevenhollidge.com/blog-source-code/slvalidation/


TODO: UI test recording (TestComplete or Telerik)


Source code

http://stevenhollidge.com/blog-source-code/SilverlightValidation.zip

Monday, 26 September 2011

Silverlight Testing Automation Tool

Unit testing out of the box with Silverlight is a real pain.  Luckily for us StatLight makes its a breeze and also provides continuous integration with Visual Studio and TeamCity.

My code below shows a nice example of an application using the MVVM Light framework.

How Does It Work?

StatLight is a console application that creates an in memory web server. It starts up a web browser that will request from the web server a page containing your test xap. By executing all the tests in the browser and communicating test results back to the web server. The console now has the ability to publish those results in manners not allowed in the Silverlight sandbox.

Visual Studio Integration (via ReSharper and AgUnit)

ScreenShot142

TeamCity Integration

ScreenShot137

TeamCity Configuration

ScreenShot139

Standard StatLight Console Output

ScreenShot141

Silverlight Test Project

Some interesting points about the Silverlight Unit Tests:

  • To use EnqueueCallback and EnqueueTestComplete you need to inherit from SilverlightTest, available within the Silverlight Toolkit SDK.
  • The method’s utilising these calls must be marked with the [Asynchronous] attribute.
  • You’ll often need to tailor your code to provide hooks for the unit tests.  For example adding an event after an action occurs so that TestMethod can subscribe to the event.

ViewModel

Downloads

http://statlight.codeplex.com

http://agunit.codeplex.com

http://stevenhollidge.com/blog-source-code/SilverlightUnitTestDemo.zip