// Arrange Act Assert

Jag Reehal on Agile Development, ASP.NET MVC, Silverlight and all manner of good stuff


Code First Entity Framework Unit Test Examples

Posted on | July 28, 2010 | No Comments

Following the release of the Entity Framework 4 CTP 4 and Scott Gu’s excellent blog post about Code-First Development with Entity Framework 4, we’ll be having a look at what your Code-First Entity Framework unit tests might look like.

The code used in this post is available here.

Remember in order to run the code or to create unit tests shown in this post you need to download and install:

Getting started

The entities we will be using are the same Dinner and RSVP entities Scott used in his post

public class Dinner
{
    public int DinnerID { get; set; }
    public string Title { get; set; }
    public DateTime EventDate { get; set; }
    public string Address { get; set; }
    public string Country { get; set; }
    public string HostedBy { get; set; }

    public virtual ICollection<RSVP> RSVPs { get; set; }
}

public class RSVP
{
    public int RsvpID { get; set; }
    public int DinnerID { get; set; }
    public string AtendeeEmail { get; set; }

    public virtual Dinner Dinner { get; set; }
}

as well as the NerdDinners class which inherits from DbContext

public class NerdDinners : DbContext
{
    public DbSet<Dinner> Dinners { get; set; }
    public DbSet<RSVP> RSVP { get; set; }
}

Creating Entity Framework Code-First Unit Tests

So let’s start off by writing a test to check a Dinner can be saved in the database.

[Test]
public void Should_be_able_to_save_new_dinner()
{
    // Arrange
    Database.DefaultConnectionFactory = new SqlCeConnectionFactory("System.Data.SqlServerCe.4.0");
    NerdDinners nerdDinners = new NerdDinners();

    Dinner dinner = new Dinner
                        {
                            Title = "Dinner with the Queen",
                            Address = "Buckingham Palace",
                            EventDate = DateTime.Now,
                            HostedBy = "Liz and Phil",
                            Country = "England"
                        };

    nerdDinners.Dinners.Add(dinner);

    // Act
    nerdDinners.SaveChanges();

    // Assert
    Dinner savedDinner = (from d in nerdDinners.Dinners
                            where d.DinnerID == dinner.DinnerID
                            select d).Single();

    savedDinner.Title.ShouldEqual(dinner.Title);
    savedDinner.Address.ShouldEqual(dinner.Address);
    savedDinner.EventDate.ShouldEqual(dinner.EventDate);
    savedDinner.HostedBy.ShouldEqual(dinner.HostedBy);
    savedDinner.Country.ShouldEqual(dinner.Country);
}

There are a couple of things to note here.

In the LINQ query to get the saved Dinner from the database we can use the ID of the Dinner we created because when you call the SaveChanges() method the Entity Framework will set the identity value of the object(s) being persisted.

The other thing we could have done is use a ‘domain signature’ to check for equality, but that’s for a future blog post.

Testing entities with foreign keys

The code below shows a test for saving an RSVP.

[Test]
public void Should_be_able_to_save_new_rsvp()
{
    // Arrange
    Database.DefaultConnectionFactory = new SqlCeConnectionFactory("System.Data.SqlServerCe.4.0");
    NerdDinners nerdDinners = new NerdDinners();

    RSVP rsvp = new RSVP();
    rsvp.AtendeeEmail = "someone@somedomain.com";
    Dinner dinner = new Dinner
                        {
                            Title = "Dinner with the Queen",
                            Address = "Buckingham Palace",
                            EventDate = DateTime.Now,
                            HostedBy = "Liz and Phil",
                            Country = "England"
                        };
    rsvp.Dinner = dinner;

    nerdDinners.RSVP.Add(rsvp);

    // Act
    nerdDinners.SaveChanges();

    // Assert
    RSVP savedRSVP = (from s in nerdDinners.RSVP
                        where s.RsvpID == rsvp.RsvpID
                        select s).Single();

    savedRSVP.AtendeeEmail.ShouldEqual(rsvp.AtendeeEmail);
}

One thing you might have noticed here is that we had to create a Dinner as well as an RSVP. This is because of the foreign key constraint for the DinnerID.

So at this point you could be asking why we can’t use the Dinner we created in the first test? The trouble, danger and bad practice of doing that is falling into the trap of creating a dependency of your tests running in some sort of order or sequence.

AlwaysRecreateDatabase

In his post Scott created a NerdDinnersInitializer class which inherited from RecreateDatabaseIfModelChanges. But this is not good enough for a unit test because we need to ensure each test starts off in a known state.

This doesn’t mean we have to create a Dinner each time we want to save an RSVP because we can create an NerdDinnersInitializer which is already populated with a dinner by overriding the Seed method.

public class NerdDinnersInitializer : AlwaysRecreateDatabase<NerdDinners>
{
    protected override void Seed(NerdDinners context)
    {
        var dinners = new List<Dinner> { new Dinner()
                                                {
                                                    Title = "Dinner with the Queen",
                                                    Address = "Buckingham Palace",
                                                    EventDate = DateTime.Now,
                                                    HostedBy = "Liz and Phil",
                                                    Country = "England"
                                                }
        };
        dinners.ForEach(d => context.Dinners.Add(d));
    }
}

And use it in a test to check we can create an RSVP

[Test]
public void Should_be_able_to_save_new_rsvp_using_existing_dinner()
{
    // Arrange
    Database.DefaultConnectionFactory = new SqlCeConnectionFactory("System.Data.SqlServerCe.4.0");
    Database.SetInitializer<NerdDinners>(new NerdDinnersInitializer());
    NerdDinners nerdDinners = new NerdDinners();

    RSVP rsvp = new RSVP();
    rsvp.AtendeeEmail = "someone@somedomain.com";
    rsvp.DinnerID = nerdDinners.Dinners.First().DinnerID;

    nerdDinners.RSVP.Add(rsvp);

    // Act
    nerdDinners.SaveChanges();

    // Assert
    RSVP savedRSVP = (from s in nerdDinners.RSVP
                        where s.RsvpID == rsvp.RsvpID
                        select s).Single();

    savedRSVP.AtendeeEmail.ShouldEqual(rsvp.AtendeeEmail);
}

The disadvantage of always creating a database is the amount of time it takes to actually create the database

So the more times you call SetInitializer in which you’re always recreating a database, the longer it will take for your tests to run.

My recommendation is to create dummy/stub dinners upfront and call SetInitializer before you run the tests. In NUnit this is done in the TestFixtureSetUp as shown below.

[TestFixtureSetUp]
public void TestFixtureSetup()
{
    Database.SetInitializer<NerdDinners>(new NerdDinnersInitializer());
}

Tests to check updates

So now you can save a Dinner, the next test you might write is to check you can update it.

[Test]
public void Should_be_able_to_update_existing_dinner()
{
    // Arrange
    NerdDinners nerdDinners = new NerdDinners();

    Dinner dinner = nerdDinners.Dinners.First();
    dinner.HostedBy = "Charlie and Camilla";

    // Act
    nerdDinners.SaveChanges();

    // Assert
    Dinner savedDinner = (from d in nerdDinners.Dinners
                            where d.DinnerID == dinner.DinnerID
                            select d).Single();

    savedDinner.HostedBy.ShouldEqual(dinner.HostedBy);
}

Testing your models

The examples in this post follow the Entity Framework convention you get out of the box.

As we have already established the property DinnerID is a foreign key in the RSVP entity.

But if you forgot to add it, the Dinner property would always be null.

The test below verifies we are able to view information about a dinner when we retrieve an RSVP from the database.

[Test]
public void Should_be_able_to_view_dinner_details()
{
    // Arrange
    NerdDinners nerdDinners = new NerdDinners();
    var dinner = nerdDinners.Dinners.First();

    RSVP rsvp = new RSVP();
    rsvp.AtendeeEmail = "someone@somedomain.com";
    rsvp.DinnerID = dinner.DinnerID;

    nerdDinners.RSVP.Add(rsvp);

    // Act
    nerdDinners.SaveChanges();

    // Assert
    RSVP savedRSVP = (from s in nerdDinners.RSVP
                        where s.RsvpID == rsvp.RsvpID
                        select s).Single();

    savedRSVP.Dinner.Title.ShouldEqual(dinner.Title);
}

Jag Reehal’s Final Thought on ‘Examples of Code First Entity Framework Unit Tests’

In this post I wanted to show a few examples of how you might create unit tests for your Entity Framework projects.

The ADO.NET team have really done a great job enabling developers to be able to do code-first development and allow them to move a step closer to doing test driven development using the Entity Framework.

Using INotifyDataErrorInfo for validation in MVVM with Silverlight

Posted on | July 16, 2010 | 1 Comment

In this post we will be looking at how validation can be done by implementing the INotifyDataErrorInfo interface for a calculator we have been building as part of the Silverlight refactoring series.

Like the IDataErrorInfo interface, the INotifyDataErrorInfo interface gives you the ability to do validation without throwing exceptions.

The full solution for this post can be downloaded here.

Note to WPF developers – INotifyDataErrorInfo isn’t available in WPF (yet)

But you can vote for INotifyDataErrorInfo to be in a future release of WPF.

Pre INotifyDataErrorInfo

As you can see in the code below we are throwing exceptions in the setters for the two values we want to add together.

public string  FirstValue
{
    get { return _firstValue; }
    set
    {
        _firstValue = value;
        try
        {
            int.Parse(_firstValue);
        }
        catch (Exception)
        {
            throw new Exception("That's not a number");
        }
        OnPropertyChanged("FirstValue");
    }
}
public string  SecondValue
{
    get { return _secondValue; }
    set
    {
        _secondValue = value;
        try
        {
            int.Parse(_secondValue);
        }
        catch (Exception)
        {
            throw new Exception("That's not a number");
        }
        OnPropertyChanged("SecondValue");
    }
}

Implementing the INotifyDataErrorInfo interface

As we only want the calculate button to be enabled when the user has entered valid numbers to add together, we need to keep track of any validation errors.

Similar to how we have done in other posts, we will use a class for storing validation errors instead of making it the responsibility of the ViewModel.

And that class is the EntityBase class, which I borrowed from Mike Taulty. Cheers Mike!

The code below shows how the EntityBase class implements the ErrorsChanged event, GetErrors method and the HasErrors property defined in the INotifyDataErrorInfo interface.

public class EntityBase : INotifyDataErrorInfo
{
    public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
    readonly Dictionary<string, List<string>> _currentErrors;

    public EntityBase()
    {
        _currentErrors = new Dictionary<string, List<string>>();
    }

    public IEnumerable GetErrors(string propertyName)
    {
        if (string.IsNullOrEmpty(propertyName))
        {
            return (_currentErrors.Values);
        }

        MakeOrCreatePropertyErrorList(propertyName);
        return _currentErrors[propertyName];
    }

    public bool HasErrors
    {
        get
        {
            return (_currentErrors.Where(c => c.Value.Count > 0).Count() > 0);
        }
    }

    void FireErrorsChanged(string property)
    {
        if (ErrorsChanged != null)
        {
            ErrorsChanged(this, new DataErrorsChangedEventArgs(property));
        }
    }
    public void ClearErrorFromProperty(string property)
    {
        MakeOrCreatePropertyErrorList(property);
        _currentErrors[property].Clear();
        FireErrorsChanged(property);
    }
    public void AddErrorForProperty(string property, string error)
    {
        MakeOrCreatePropertyErrorList(property);
        _currentErrors[property].Add(error);
        FireErrorsChanged(property);
    }

    void MakeOrCreatePropertyErrorList(string propertyName)
    {
        if (!_currentErrors.ContainsKey(propertyName))
        {
            _currentErrors[propertyName] = new List<string>();
        }
    }
}

The EnitityBase class can be unit tested like this

[TestFixture]
public class When_using_the_EntityBase
{
    private EntityBase _entityBase;

    [SetUp]
    public void SetUp()
    {
        _entityBase = new EntityBase();
    }

    [Test]
    public void HasErrors_should_return_true_when_errors_exist()
    {
        // Arrange
        _entityBase.AddErrorForProperty("X", "X");

        // Act
        var result = _entityBase.HasErrors;

        // Assert
        result.ShouldBeTrue();
    }

    [Test]
    public void HasErrors_should_return_true_when_no_errors_exist()
    {
        // Arrange
        // collection will be empty at this point

        // Act
        var result = _entityBase.HasErrors;

        // Assert
        result.ShouldBeFalse();
    }

    [Test]
    public void Should_be_able_to_clear_error_from_property()
    {
        // Arrange
        _entityBase.AddErrorForProperty("X", "X");

        // Act
        _entityBase.ClearErrorFromProperty("X");
        var result = _entityBase.GetErrors("X") as List<string>; 

        // Assert
        result.Count().ShouldEqual(0);

    }

    [Test]
    public void Should_be_able_to_get_error_for_property()
    {
        // Arrange
        const string errorMessage = "ErrorMessage";
        _entityBase.AddErrorForProperty("X", "ErrorMessage");

        // Act
        var result =  _entityBase.GetErrors("X") as List<string>;

        // Assert
        result[0].ShouldEqual(errorMessage);

    }
}

How the ViewModel validates user input

We need to validate the users input each time the value of a property changes.

If you have been following the series you’ll know the benefits of injecting/importing a class responsible for validation, the CalculatorValidator, into the ViewModel and to validate the users input.

In the code for the CalculatorValidator class, the Validate method could have returned a collection of error messages, but to keep this example simple we’ll just return the first validation error we encounter.

[Export(typeof(ICalculatorValidator))]
public class CalculatorValidator : ICalculatorValidator
{
    [ImportMany]
    public IEnumerable<ICalculatorValidationRule> CalculatorValidationRules { get; set; }

    public ValidationResult Validate(string value)
    {
        List<ValidationResult> validationResults = new List<ValidationResult>();
        foreach (var calculatorValidationRule in CalculatorValidationRules)
        {
            if (!calculatorValidationRule.IsValid(value))
            {
                return new ValidationResult()
                            {
                                IsValid = false,
                                ErrorMessage = calculatorValidationRule.ErrorMessage

                            };
            }
        }
        return new ValidationResult() { IsValid = true };
    }
}

public class ValidationResult
{
    public bool IsValid { get; set; }
    public string ErrorMessage { get; set; }
}

If you’re new to the series the validation rules for calculator are being imported by MEF. Read how and why we are doing this in the ‘Applying the Open Closed Principle in Silverlight and WPF using MEF‘ post.

Using the INotifyDataErrorInfo interface in the ViewModel

In the code for the ViewModel shown below take note of how:

  • the ViewModel inherits from the EntityBase class
  • the CheckIfNumberIsValid method is called whenever a property value changes
  • the INotifyDataErrorInfo HasErrors property is used to determine if the button should be enabled in the CalculatorViewModel_ErrorsChanged handler for the ErrorsChanged event. This is one of the advantages INotifyDataErrorInfo has over IDataErrorInfo.
[Export]
public class CalculatorViewModel : EntityBase, INotifyPropertyChanged
{
    private string _firstValue;
    private string _secondValue;
    private string _result;       

    private readonly ICalculator _calculator;
    private readonly RelayCommand _calculateCommand;

    public event PropertyChangedEventHandler PropertyChanged;
    public ObservableCollection<string> FirstValueErrors { get; set; }
    private readonly ICalculatorValidator _calculatorValidator;

    [ImportingConstructor]
    public CalculatorViewModel(ICalculator calculator, ICalculatorValidator calculatorValidator)
    {
        _calculator = calculator;
        _calculatorValidator = calculatorValidator;
        _calculateCommand = new RelayCommand(Calculate) { IsEnabled = true };
        ErrorsChanged += new EventHandler<DataErrorsChangedEventArgs>(CalculatorViewModel_ErrorsChanged);

        _firstValue = "0";
        _secondValue = "0";
    }

    void CalculatorViewModel_ErrorsChanged(object sender, DataErrorsChangedEventArgs e)
    {
        _calculateCommand.IsEnabled = HasErrors == false;
    }

    public void Calculate()
    {
        Result = _calculator.Add(Convert.ToInt32(FirstValue), Convert.ToInt32(SecondValue)).ToString();
    }

    public string FirstValue
    {
        get { return _firstValue; }
        set
        {
            _firstValue = value;
            CheckIfNumberIsValid("FirstValue", value);
        }
    }

    public string SecondValue
    {
        get { return _secondValue; }
        set
        {
            _secondValue = value;
            CheckIfNumberIsValid("SecondValue", value);
        }
    }

    public void CheckIfNumberIsValid(string propertyName, string value)
    {
        ClearErrorFromProperty(propertyName);

        var validationResult = _calculatorValidator.Validate(value);
        if (validationResult.IsValid  == false)
        {
            AddErrorForProperty(propertyName, validationResult.ErrorMessage);
        }
        OnPropertyChanged(propertyName);
    }

    public string Result
    {
        get { return _result; }
        private set
        {
            _result = value;
            OnPropertyChanged("Result");
        }
    }

    public RelayCommand CalculateCommand
    {
        get { return _calculateCommand; }
    }

    protected void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this,
                new PropertyChangedEventArgs(propertyName));
        }
    }
}

XAML changes for INotifyDataErrorInfo

The final change required to implement INotifyDataErrorInfo interface is to change the text box bindings and set ValidatesOnNotifyDataErrors=True

<TextBox Text="{Binding FirstValue, Mode=TwoWay, ValidatesOnNotifyDataErrors=True}"/>
<TextBox Text="{Binding SecondValue, Mode=TwoWay, ValidatesOnNotifyDataErrors=True}"/>

So what have we achieved?

In this post we have refactored the code to use the INotifyDataErrorInfo interface and are no longer throwing exceptions to do validation.

As well as allowing you return multiple validation errors for a property, the INotifyDataErrorInfo interface can be used for asynchronous data validation as demonstrated by Jesse Liberty in this video.

Using IDataErrorInfo for validation in MVVM with Silverlight and WPF

Posted on | July 7, 2010 | 1 Comment

In this post we will be looking at how validation can be done by implementing the IDataErrorInfo interface for a calculator we have been building as part of the Silverlight refactoring series.

The IDataErrorInfo interface gives you the ability to do validation without throwing exceptions.

The full solution for this post can be downloaded here.

Pre IDataErrorInfo

As you can see in the code below we are throwing exceptions in the setters for the two values we want to add together.

public string  FirstValue
{
    get { return _firstValue; }
    set
    {
        _firstValue = value;
        try
        {
            int.Parse(_firstValue);
        }
        catch (Exception)
        {
            throw new Exception("That's not a number");
        }
        OnPropertyChanged("FirstValue");
    }
}
public string  SecondValue
{
    get { return _secondValue; }
    set
    {
        _secondValue = value;
        try
        {
            int.Parse(_secondValue);
        }
        catch (Exception)
        {
            throw new Exception("That's not a number");
        }
        OnPropertyChanged("SecondValue");
    }
}

Implementing the IDataErrorInfo interface

The IDataErrorInfo interface consists of two properties.

string this[string columnName] {get;}
string Error {get;}

For the Error property we can just return null because we don’t want to return a single error message for the entire object.

public string Error
{
    get { return null; }
}

For the property which returns an error for a text box we could do the validation like this

public string this[string columnName]
{
    get
    {
        string error = null;
        switch (columnName)
        {
            case "FirstValue":
                try
                {
                    int.Parse(_firstValue);
                }
                catch (Exception)
                {
                    error = "That is not a number";
                }
                break;
            case "SecondValue":
                try
                {
                    int.Parse(_firstValue);
                }
                catch (Exception)
                {
                    error = "That is not a number";
                }
                break;
        }
        return error;
    }
}

But as we saw in a previous post about using ValidatesOnExceptions to do validation it’s much easier to write unit tests when there are separation of concerns and the ViewModel is not responsible for validation.

So this means we need to create a class for storing the validation error for each textbox

public class ValidationBase
{
    public readonly Dictionary<string, string> Errors;

    public ValidationBase()
    {
        Errors = new Dictionary<string, string>();
    }

    public void AddError(string propertyName, string message)
    {
        if (!Errors.ContainsKey(propertyName))
        {
            Errors[propertyName] = message;
        }
    }

    public void RemoveErrors(string propertyName)
    {
        Errors.Remove(propertyName);
    }

    public string GetErrorMessageForProperty(string propertyName)
    {
        string message;
        Errors.TryGetValue(propertyName, out message);
        return message;
    }

    public bool HasErrors()
    {
        return Errors.Count != 0;
    }
}

which is inherited by a CalculatorValidator class that returns a boolean value if the property value is not valid

[Export(typeof(ICalculatorValidator))]
public class CalculatorValidator : ValidationBase, ICalculatorValidator
{
    [ImportMany]
    public IEnumerable<ICalculatorValidationRule> CalculatorValidationRules { get; set; }

    public bool IsPropertyValid(string propertyName, string value)
    {
        RemoveErrors(propertyName);
        foreach (var calculatorValidationRule in CalculatorValidationRules)
        {
            if (!calculatorValidationRule.IsValid(value))
            {
                AddError(propertyName, calculatorValidationRule.ErrorMessage);
                return false;
            }
        }
        return true;
    }
}

If you’re new to the series the validation rules for calculator are being imported by MEF. Read how and why we are doing this in the ‘Applying the Open Closed Principle in Silverlight and WPF using MEF‘ post.

Now we can inject/import the CalculatorValidator into the ViewModel and use it to validate the users input.

As we only want the user to be able to click the calculate button when the form is valid we call we the CheckIfCalculteButtonShouldBeEnabled method when a text box value has changed.

[Export]
public class CalculatorViewModel : INotifyPropertyChanged, IDataErrorInfo
{
    private string _firstValue;
    private string _secondValue;
    private string _result;

    private readonly ICalculator _calculator;
    private readonly RelayCommand _calculateCommand;

    public event PropertyChangedEventHandler PropertyChanged;
    private readonly ICalculatorValidator _calculatorValidator;

    [ImportingConstructor]
    public CalculatorViewModel(ICalculator calculator, ICalculatorValidator calculatorValidator)
    {
        _calculator = calculator;
        _calculatorValidator = calculatorValidator;
        _calculateCommand = new RelayCommand(Calculate) { IsEnabled = true };

        _firstValue = "0";
        _secondValue = "0";
    }
    public void Calculate()
    {
        Result = _calculator.Add(Convert.ToInt32(FirstValue), Convert.ToInt32(SecondValue)).ToString();
    }

    public string FirstValue
    {
        get { return _firstValue; }
        set
        {
            _firstValue = value;
            OnPropertyChanged("FirstValue");
        }
    }

    public string SecondValue
    {
        get { return _secondValue; }
        set
        {
            _secondValue = value;
            OnPropertyChanged("SecondValue");
        }
    }

    public void CheckIfCalculteButtonShouldBeEnabled()
    {
        _calculateCommand.IsEnabled = _calculatorValidator.HasErrors() == false;
    }

    public string Result
    {
        get { return _result; }
        private set
        {
            _result = value;
            OnPropertyChanged("Result");
        }
    }

    public RelayCommand CalculateCommand
    {
        get { return _calculateCommand; }
    }

    protected void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this,
                new PropertyChangedEventArgs(propertyName));
        }
    }

    public string this[string columnName]
    {
        get
        {
            string error = null;
            switch (columnName)
            {
                case "FirstValue":
                    error = ValidateNumber("FirstValue", _firstValue);
                    break;
                case "SecondValue":
                    error = ValidateNumber("SecondValue", _secondValue);
                    break;
            }

            CheckIfCalculteButtonShouldBeEnabled();
            return error;
        }
    }

    public string ValidateNumber(string propertyName, string value)
    {
        if (!_calculatorValidator.IsPropertyValid(propertyName, value))
        {
            return _calculatorValidator.GetErrorMessageForProperty(propertyName);
        }
        return null;
    }

    public string Error
    {
        get { return null; }
    }
}

The code below shows how we can unit test the ViewModel which implements the IDataErrorInfo interface.

[TestFixture]
public class When_using_the_CalculatorViewModel
{
    private Mock<ICalculator> _calculator;
    private Mock<ICalculatorValidator> _calculatorValidator;
    private CalculatorViewModel _calculatorViewModel;

    [SetUp]
    public void SetUp()
    {
        _calculator = new Mock<ICalculator>();
        _calculatorValidator = new Mock<ICalculatorValidator>();
        _calculatorViewModel = new CalculatorViewModel(_calculator.Object, _calculatorValidator.Object);
    }

    [Test]
    public void Initial_value_of_first_number_is_0()
    {
        // Arrange
        // checking initial value

        // Act
        var result = _calculatorViewModel.FirstValue;

        // Assert
        result.ShouldEqual("0");
    }

    [Test]
    public void Initial_value_of_second_number_is_0()
    {
        // Arrange
        // checking initial value

        // Act
        var result = _calculatorViewModel.SecondValue;

        // Assert
        result.ShouldEqual("0");
    }

    [Test]
    public void Initial_value_of_calculate_button_is_enabled()
    {
        // Arrange
        // checking initial value

        // Act
        var result = _calculatorViewModel.CalculateCommand.IsEnabled;

        // Assert
        result.ShouldBeTrue();
    }

    [Test]
    public void ValidateNumber_returns_null_if_value_is_valid()
    {
        // Arrange
        _calculatorValidator.Setup(c => c.IsPropertyValid("X","X")).Returns(true);

        // Act
        var result = _calculatorViewModel.ValidateNumber("X","X");

        // Assert
        result.ShouldBeNull();
    }

    [Test]
    public void ValidateNumber_returns_error_message_if_value_is_not_valid()
    {
        // Arrange
        const string errorMessage = "ErrorMessageText";
        _calculatorValidator.Setup(c => c.IsPropertyValid("X", "X")).Returns(false);
        _calculatorValidator.Setup(c => c.GetErrorMessageForProperty("X")).Returns(errorMessage);

        // Act
        var result = _calculatorViewModel.ValidateNumber("X", "X");

        // Assert
        result.ShouldEqual(errorMessage);
    }

    [Test]
    public void Calculate_command_should_not_be_enabled_if_ViewModel_is_not_valid()
    {
        // Arrange
        _calculatorValidator.Setup(c => c.HasErrors()).Returns(true);

        // Act
        _calculatorViewModel.CheckIfCalculteButtonShouldBeEnabled();

        // Assert
        _calculatorViewModel.CalculateCommand.IsEnabled.ShouldBeFalse();
    }

    [Test]
    public void Calculate_command_should_be_enabled_if_ViewModel_is_valid()
    {
        // Arrange
        _calculatorValidator.Setup(c => c.HasErrors()).Returns(false);

        // Act
        _calculatorViewModel.CheckIfCalculteButtonShouldBeEnabled();

        // Assert
        _calculatorViewModel.CalculateCommand.IsEnabled.ShouldBeTrue();
    }
}

The final change we need to make is to change the text box binding to ValidatesOnDataErrors=True in the XAML file.

<TextBox Text="{Binding FirstValue, Mode=TwoWay, ValidatesOnDataErrors=True}"/>
<TextBox Text="{Binding SecondValue, Mode=TwoWay, ValidatesOnDataErrors=True}"/>

So what have we achieved?

In this post we have refactored the code to use the IDataErrorInfo interface and are no longer throwing exceptions to do validation.

Whether you choose to use it or not depends if you want multiple errors for a single property to be combined into a single error message.

Enabling buttons in Silverlight and WPF using MVVM and ValidatesOnExceptions

Posted on | July 6, 2010 | No Comments

In a previous post we saw how exceptions could be used for Silverlight validation.

While could validate the users input using exceptions, it wasn’t possible to disable the calculate button if the input values were invalid (because they were either blank or non-numeric).

The code used in this post can be downloaded here.

So how are we going to solve the problem?

Throughout the Silverlight refactoring series I’ve tried to illustrate how important SOLID design principles are for having testable applications.

So if we think about the ViewModel, we need to ask ourselves if it’s the right place or should be responsible for validation?

In this case I would say no.

When should the button be enabled?

For a calculate button to be enabled, both text boxes must contain numeric values

This means we have to know if both text boxes are valid at the same time. Taking a step back here, let’s think about the bigger picture.

What if there are three or four text boxes?

What we really after is a class that will be responsible for knowing if any text boxes are invalid.

This can be done by using a validation base class.

In the code below notice how the ValidationBase class doesn’t know anything about enabling or disabling the calculate button.

public class ValidationBase
{
    public readonly Dictionary<string, string> Errors;

    public ValidationBase()
    {
        Errors = new Dictionary<string, string>();
    }

    public void AddError(string propertyName, string message)
    {
        if (!Errors.ContainsKey(propertyName))
        {
            Errors[propertyName] = message;
        }
    }

    public void RemoveErrors(string propertyName)
    {
        Errors.Remove(propertyName);
    }

    public bool IsPropertyValid(string propertyName)
    {
        return !Errors.ContainsKey(propertyName);
    }

    public string GetErrorMessageForProperty(string propertyName)
    {
        string message;
        Errors.TryGetValue(propertyName, out message);
        return message;
    }

    public bool IsValid()
    {
        return Errors.Count == 0;
    }
}

The code below shows the unit tests for the ValidationBase class.

[TestFixture]
public class When_using_the_ValidatiorBase
{
    private ValidationBase _validationBase;

    [SetUp]
    public void SetUp()
    {
        _validationBase = new ValidationBase();
    }

    [Test]
    public void IsValid_should_return_false_when_errors_exist()
    {
        // Arrange
        _validationBase.AddError("propertyName", "message");

        // Act
        var result = _validationBase.IsValid();

        // Assert
        result.ShouldBeFalse();
    }

    [Test]
    public void IsValid_should_return_true_when_no_errors_exist()
    {
        // Arrange
        // collection will be empty at this point

        // Act
        var result = _validationBase.IsValid();

        // Assert
        result.ShouldBeTrue();
    }

    [Test]
    public void IsPropertyValid_should_return_false_if_error_exists()
    {
        // Arrange
        _validationBase.AddError("propertyName", "message");

        // Act
        var result = _validationBase.IsPropertyValid("propertyName");

        // Assert
        result.ShouldBeFalse();
    }

    [Test]
    public void IsPropertyValid_should_return_true_if_error_does_not_exist()
    {
        // Arrange
        // collection will be empty at this point

        // Act
        var result = _validationBase.IsPropertyValid("X");

        // Assert
        result.ShouldBeTrue();
    }

    [Test]
    public void Should_be_able_to_return_message_for_error()
    {
        // Arrange
        _validationBase.AddError("propertyName", "message");

        // Act
        var result = _validationBase.GetErrorMessageForProperty("propertyName");

        // Assert
        result.ShouldEqual("message");
    }

    [Test]
    public void Should_return_null_if_message_does_not_exist_for_error()
    {
        // Arrange
        // collection will be empty at this point

        // Act
        var result = _validationBase.GetErrorMessageForProperty("propertyName");

        // Assert
        result.ShouldBeNull();
    }
}

Validating the users input

There are three outcomes when validating what the user has entered:

  • The value is blank
  • The value is not a number
  • The value is a number

All the ViewModel wants to know is if the users input is valid, choosing the appropriate error message isn’t its concern. This means we need a class that will be responsible for validation and returning the relevant message.

For this we will use the CalculatorValidator class we created in the ‘Applying the Open Closed Principle in Silverlight and WPF using MEF‘ post.

[Export(typeof(ICalculatorValidator))]
public class CalculatorValidator : ValidationBase, ICalculatorValidator
{
    [ImportMany]
    public IEnumerable<ICalculatorValidationRule> CalculatorValidationRules { get; set; }

    public void ValidateNumber(string propertyName, string value)
    {
        RemoveErrors(propertyName);

        foreach (var calculatorValidationRule in CalculatorValidationRules)
        {
            if (!calculatorValidationRule.IsValid(value))
            {
                AddError(propertyName, calculatorValidationRule.ErrorMessage);
                return;
            }
        }
    }
}

This is useful because if we decide to change how to validate the user’s input neither the CalculatorValidator or the ViewModel classes need to be modified.

Hooking it all up

To use the CalculatorValidator in the ViewModel it has to be injected/imported.

[ImportingConstructor]
public CalculatorViewModel(ICalculator calculator, ICalculatorValidator calculatorValidator)
{
    _calculator = calculator;
    _calculatorValidator = calculatorValidator;
    ...
}

Each time a user enters a value in the text boxes the CheckIfNumberIsValid method checks if the calculate button should be enabled and throws an exception if the users value is not valid.

public string FirstValue
{
    get { return _firstValue; }
    set
    {
        CheckIfNumberIsValid("FirstValue", out _firstValue, value);
    }
}

public string SecondValue
{
    get { return _secondValue; }
    set
    {
        CheckIfNumberIsValid("SecondValue", out _secondValue, value);
    }
}

public void CheckIfNumberIsValid(string propertyName, out string propertyValue, string value)
{
    _calculatorValidator.ValidateNumber(propertyName, value);

    CheckIfCalculteButtonShouldBeEnabled();

    if (_calculatorValidator.IsPropertyValid(propertyName))
    {
        propertyValue = value;
        OnPropertyChanged(propertyName);
    }
    else
    {
        throw new Exception(_calculatorValidator.GetErrorMessageForProperty(propertyName));
    }
}

public void CheckIfCalculteButtonShouldBeEnabled()
{
    _calculateCommand.IsEnabled = _calculatorValidator.IsValid();
}

Unit testing the ViewModel in MVVM

By using Moq we can unit test the ViewModel to ensure the button is enabled when there are no validation errors and not enabled when there are validation errors.

[TestFixture]
public class When_using_the_CalculatorViewModel
{
    private Mock<ICalculator> _calculator;
    private Mock<ICalculatorValidator> _calculatorValidator;
    private CalculatorViewModel _calculatorViewModel;

    [SetUp]
    public void SetUp()
    {
        _calculator = new Mock<ICalculator>();
        _calculatorValidator = new Mock<ICalculatorValidator>();
        _calculatorViewModel = new CalculatorViewModel(_calculator.Object, _calculatorValidator.Object);
    }

    [Test]
    public void Initial_value_of_first_number_is_0()
    {
        // Arrange
        // checking initial value

        // Act
        var result = _calculatorViewModel.FirstValue;

        // Assert
        result.ShouldEqual("0");
    }

    [Test]
    public void Initial_value_of_second_number_is_0()
    {
        // Arrange
        // checking initial value

        // Act
        var result = _calculatorViewModel.SecondValue;

        // Assert
        result.ShouldEqual("0");
    }

    [Test]
    public void Initial_value_of_calculate_button_is_enabled()
    {
        // Arrange
        // checking initial value

        // Act
        var result = _calculatorViewModel.CalculateCommand.IsEnabled;

        // Assert
        result.ShouldBeTrue();
    }

    [Test]
    [ExpectedException(typeof(Exception))]
    public void Will_throw_exception_if_input_is_invalid()
    {
        // Arrange
        string propertyValue;
        _calculatorValidator.Setup(c => c.IsPropertyValid("X")).Throws(new Exception());

        // Act
        _calculatorViewModel.CheckIfNumberIsValid("X", out propertyValue, "X");

        // Assert
        // should throw exception
    }

    [Test]
    public void Will_set_property_value_if_input_is_valid()
    {
        // Arrange
        string propertyValue;
        _calculatorValidator.Setup(c => c.IsPropertyValid("X")).Returns(true);

        // Act
        _calculatorViewModel.CheckIfNumberIsValid("X", out propertyValue, "11");

        // Assert
        propertyValue.ShouldEqual("11");

    }

    [Test]
    public void Calculate_command_should_not_be_enabled_if_ViewModel_is_not_valid()
    {
        // Arrange
        _calculatorValidator.Setup(c => c.IsValid()).Returns(false);

        // Act
        _calculatorViewModel.CheckIfCalculteButtonShouldBeEnabled();

        // Assert
        _calculatorViewModel.CalculateCommand.IsEnabled.ShouldBeFalse();
    }

    [Test]
    public void Calculate_command_should_be_enabled_if_ViewModel_is_valid()
    {
        // Arrange
        _calculatorValidator.Setup(c => c.IsValid()).Returns(true);

        // Act
        _calculatorViewModel.CheckIfCalculteButtonShouldBeEnabled();

        // Assert
        _calculatorViewModel.CalculateCommand.IsEnabled.ShouldBeTrue();
    }
}

So what have we achieved?

By using a validation base class we are able to store validation errors and can determine if the controls on the page are all valid.

The ViewModel can take advantage of this functionality and use it to enable and disable the calculate button.

Using exceptions for validation isn’t every developers cup of tea, so be sure to keep an eye on the Silverlight refactoring series to see other approaches we can take to do validation in Silverlight 4.

Validation in Silverlight and WPF using ValidatesOnExceptions

Posted on | July 1, 2010 | No Comments

With the application as it is the user is able to enter non-numeric values and add them together.

Clicking the calculate button to add two non-numeric values together will cause the application to do nothing and the user will have no idea why.

Try it for yourself here.

It would be common sense to validate what the user has entered and let them know if and what the problem is.

What I’ve seen most beginners do for validation in Silverlight and WPF

One of easiest way (in terms of the amount of code you have to write) to do validation in Silverlight and WPF is to use exceptions.

To do this we need to make changes in the ViewModel and the Calculator XAML file.

In the ViewModel an exception needs to be thrown when the input value cannot be converted to a number.

public string FirstValue
{
    get { return _firstValue; }
    set
    {
        _firstValue = value;
        try
        {
            int.Parse(_firstValue);
        }
        catch (Exception)
        {
            throw;
        }
        OnPropertyChanged("FirstValue");
    }
}

In the XAML file we set ValidatesOnExceptions equal to true for the text box binding.

<TextBox Grid.Column="0" Text="{Binding FirstValue, Mode=TwoWay, ValidatesOnExceptions=True}" Height="25" TextAlignment="Right"/>

The screenshot below shows what happens if the user does not enter a number into the text box.

Default Silverlight Exception

As you can see error message isn’t very user friendly.

To resolve this issue we could set the message of the exception thrown when parsing a number but we would be repeating/duplicating code when validating the SecondValue.

public string FirstValue
{
    get { return _firstValue; }
    set
    {
        _firstValue = value;
        try
        {
            int.Parse(_firstValue);
        }
        catch (Exception)
        {
            throw new Exception("That's not a number");
        }
        OnPropertyChanged("FirstValue");
    }
}

public string SecondValue
{
    get { return _secondValue; }
    set
    {
        _secondValue = value;
        try
        {
            int.Parse(_firstValue);
        }
        catch (Exception)
        {
            throw new Exception("That's not a number");
        }
        OnPropertyChanged("SecondValue");
    }
}

Silverlight validations the Don’t Repeat Yourself Way

A better way would to do this is by creating a reusable method for validating the users input.

void ValidateNumber(string value)
{
    try
    {
        int.Parse(value);
    }
    catch (Exception)
    {
        throw new Exception("That's not a number");
    }
}

which could be used like this

public string FirstValue
{
    get { return _firstValue; }
    set
    {
        _firstValue = value;
        ValidateNumber(value);
        OnPropertyChanged("FirstValue");
    }
}

public string SecondValue
{
    get { return _secondValue; }
    set
    {
        _secondValue = value;
        ValidateNumber(value);
        OnPropertyChanged("SecondValue");
    }
}

Now when a user enters an invalid number the they would see an error that looks like this

Custom Silverlight Exception

So what have we achieved?

With a few lines of code we are able to validate the users input and let them know what the problem is if it’s not valid.

If you have arrived here from a search engine, this post is part of series about refactoring Silverlight applications.

So if you’re thinking, this is all very well but the user is still able to click the calculate button even if they have entered invalid values to add together, see how this can prevented in the next part of the series.

keep looking »