Skip to content
This repository has been archived by the owner on Jun 16, 2024. It is now read-only.

Working with Assertions

Jordi edited this page Feb 16, 2017 · 5 revisions

Unit tests can be broken down into three sections:

  • Arrange - Initialize objects and set the value of the data that is used by the method under test.
  • Act - Invoke the method under test with.
  • Assert - Verify that the action of the method under test behaves as expected.

NB The syntax used to demonstrate here is the MSTest assertion syntax. This may be slightly different if you are using NUnit or another unit testing framework, but the basic principles still hold true.

Example 1 - Basic Assertions

Assert that something is true

// Assert that the Target Entity contains a particular attribute
Assert.IsTrue(this.Target.Contains("bsp_postcode"));

Assert that two values are equal

// Assert that the value of an attribute in the target is as expected
Assert.AreEqual(this.Target["bsp_postcode"], expectedPostcode);

Example 2.1 - Asserting that the new state has some properties

The Arrange / Act / Assert is based on the state based paradigm. Most of the cases it will be enough to just query the context at the end of the test execution to assert that the expected output is the desired output.

Assert that a particular entity record is created or with some attributes

//Assert that at at least one Account record should exist
Assert.Equal(1, fakeContext.CreateQuery<Account>().Count());
//Assert that at least one account exists with name "Microsoft"
Assert.Equal("Microsoft", fakeContext.CreateQuery<Account>().FirstOrDefault().Name);

//Or a more compact version if you want to assert both things:
var accounts = fakeContext.CreateQuery<Account>().ToList();
Assert.Equal(1, accounts.Count);
Assert.Equal("Microsoft", accounts[0].Name);

By doing that, and given that FakeXrmEasy automatically mocks queries and most methods, you can essentially do data driven unit tests in a really easy way, which is a testing model which really matches CRM development model, as in CRM pretty much is around entities (plugins, workflows, codeactivities, ... even Business Processes are saved as entities! :)).

One of the most valuable things FakeXrmEasy brings to the table is the possibility of unit testing queries, with all their associated joins, condition expressions, orders, etc, plus the ability to have also crm messages implemented which alter the state of the database, and so FakeXrmEasy emulates such behaviors with the In-Memory database.

For a comparison please check : https://dynamicsvalue.com/blog/fake-xrm-easy-versus-other-frameworks

However, there will be cases that given the complexity of the system under test, you'll need to go deeper, to, for example, check how exactly methods were called.

Let's say you have a method to Update an entity record, but you want to make sure it is called only once and only if the value is gonna change, to avoid filling up the audit history, for example. In those cases, you can still take advantage of FakeItEasy directly. Please refer to the examples below:

Example 2.2 - Asserting that certain things have happened

This is where the value of a mocking framework like fakeItEasy really comes through. Mocked objects register all method calls made during a Unit Test and we can then use this to assert that certain calls have been made, or not made. We can specify how many times they should have occurred, and with which parameter values.

Assert that a particular method was called

//// Update should have been called, just once, no matter which entity was updated
A.CallTo(() => this.Service.Update(A<Entity>._)).MustHaveHappened(Repeated.Exactly.Once);

Assert that a particular method was not called

//// Update should not have been called on any entity
A.CallTo(() => this.Service.Update(A<Entity>._)).MustHaveHappened(Repeated.Exactly.Never);

Assert that a particular method (with more than one parameter) was not called

//// Retrieve should not have been called
A.CallTo(() => this.Service.Retrieve(A<String>._, A<Guid>._, A<ColumnSet>._)).MustHaveHappened(Repeated.Never);

Assert that a particular method was called with a certain parameter

//// Update should have been called, just once, on an entity called "bsp_college" 
A.CallTo(() => this.Service.Update(A<Entity>.That.Matches(q => q.LogicalName == "bsp_college"))).MustHaveHappened(Repeated.Exactly.Once);

Assert that a particular method was called with a parameter that matches certain criteria

//// Update should have been called, just once, and the entity should contain an attribute called "bsp_comments"
A.CallTo(() => this.Service.Update(A<Entity>.That.Matches(a => a.Contains("bsp_comments")))).MustHaveHappened(Repeated.Exactly.Once);

Assert that a particular method was called with a parameter that matches certain criteria

//// Update should have been called, just once, and the entity should contain an attribute called "name" with a value the same as the "expectedName" variable
A.CallTo(() => service.Create(A<Entity>.That.Matches(a => a["name"].ToString() == expectedName))).MustHaveHappened(Repeated.Exactly.Once);

Assert that a particular method was called with multiple parameters

// Associate method has been called once, for the relationship "teamroles_association", no matter what other parameters were used
A.CallTo(() => this.Service.Associate(A<String>._, A<Guid>._, A<Relationship>.That.Matches(q => q.SchemaName == "teamroles_association"), A<EntityReferenceCollection>._)).MustHaveHappened(Repeated.Exactly.Once);

Assert that a particular method was called a certain number of times

// Create method must have been called twice
A.CallTo(() => service.Create(A<Entity>._)).MustHaveHappened(Repeated.Exactly.Twice);

// Create method must have been called at least twice
A.CallTo(() => service.Create(A<Entity>._)).MustHaveHappened(Repeated.AtLeast.Twice);

// Create method must have been called exactly 10 times
A.CallTo(() => service.Create(A<Entity>._)).MustHaveHappened(Repeated.Exactly.Times(10));