Arrange/Act/Assert (AAA) is a pattern for arranging and formatting code in Unit Test methods.
It is a best practice to author your tests in more natural and convenient way.
The idea is to develop a unit test by following these 3 simple steps:
- Arrange – setup the testing objects and prepare the prerequisites for your test
- Act – perform the actual work of the test
- Assert – verify the result
Lets illustrate this with an example.
We will test our warehouse to ensure that it returns correct results when an order is placed.
Arrange
First we need an order:
CopyC#
var order = new Order("Camera", 2);
CopyVB
Dim order = New Order("Camera", 2)Now let’s mock the warehouse:
CopyC#
var warehouse = Mock.Create<IWarehouse>();
CopyVB
Dim warehouse = Mock.Create(Of IWarehouse)()
We want to ensure that when an order of 2 cameras is placed the warehouse returns that it has availability in the inventory.
CopyC#
Mock.Arrange(() => warehouse.HasInventory("Camera", 2)).Returns(true);
CopyVB
Mock.Arrange(Function() warehouse.HasInventory("Camera", 2)).Returns(true)That’s it. We set up the testing objects for our test. Now let’s act.
Act
Fill our order from the warehouse.
CopyC#
CopyVB
Now we want to ensure that our order was actually filled meaning that the warehouse really had inventory of 2 cameras.
Assert
We will use the Assert class from Microsoft.VisualStudio.TestTools.UnitTesting namespace (found in Microsoft.VisualStudio.QualityTools.UnitTestFramework assembly – automatically added as a reference from Visual Studio while creating a Test Project) to ensure that the IsFilled property of the order is set to true.
CopyC#
Assert.IsTrue(order.IsFilled);
CopyVB
Assert.IsTrue(order.IsFilled)
With this simple example we illustrated the use of the AAA pattern and showed how easy it is to test your code with Telerik JustMock. Notice that you don’t need to change even a single line of your original code to set up, execute and verify its correctness.
Verify Interaction
Now let's take it a little further and verify not only the final result, but also the interaction while executing the test.
We arranged that when the warehouse’s HasInventory method is called with specific parameters, it should return true, but we never ensured that this method is actually called. Let's change the Arrange method and mark that warehouse.HasInventory must be called.
CopyC#
Mock.Arrange(() => warehouse.HasInventory("Camera", 2)).Returns(true).MustBeCalled();
CopyVB
Mock.Arrange(Function() warehouse.HasInventory("Camera", 2)).Returns(true).MustBeCalled()To verify this we need to call Mock.Assert in the Assert phase with the warehouse object.
CopyC#
CopyVB
Verify calls order
Furthermore you may want to ensure that a set of method calls are executed in a particular order. To do this you use the Arrange method to define the methods invocation order.
CopyC#
[TestMethod]
public void ShouldVerifyCallsOrder()
{
var foo = Mock.Create<IFoo>();
Mock.Arrange(() => foo.Submit()).InOrder();
Mock.Arrange(() => foo.Echo()).InOrder();
foo.Submit();
foo.Echo();
Mock.Assert(foo);
}
CopyVB
<TestMethod()>
Public Sub ShouldVerifyCallsOrder()
Dim foo = Mock.Create(Of IFoo)()
Mock.Arrange(Sub() foo.Submit()).InOrder()
Mock.Arrange(Sub() foo.Echo()).InOrder()
foo.Submit()
foo.Echo()
Mock.Assert(foo)
End SubAgain to verify this we need to call Mock.Assert in the Assert phase with the foo object.
Note that the InOrder option also supports asserting the order of mock calls regardless of the instance within the test scope.
Imagine that you have to validate that the user has logged in before using his/hers shopping cart in your application.
CopyC#
public interface IUserValidationService
{
int ValidateUser(string userName, string password);
}
public interface IShoppingCartService
{
IList<string> LoadCart(int userID);
}
CopyVB
Public Interface IUserValidationService
Function ValidateUser(ByVal userName As String, ByVal password As String) As Integer
End Interface
Public Interface IShoppingCartService
Function LoadCart(ByVal userID As Integer) As IList(Of String)
End InterfaceHere we have defined the IUserValidationService and the IShoppingCartService services whose invocation order we are going to assert in the following test:
CopyC#
[TestMethod]
public void ShouldAssertInOrderForDifferentInstancesInTestMethodScope()
{
string userName = "Bob";
string password = "Password";
int userID = 5;
var cart = new List<string> {"Foo", "Bar"};
var userServiceMock = Mock.Create<IUserValidationService>();
var shoppingCartServiceMock = Mock.Create<IShoppingCartService>();
Mock.Arrange(() => userServiceMock.ValidateUser(userName, password)).Returns(userID).InOrder().OccursOnce();
Mock.Arrange(() => shoppingCartServiceMock.LoadCart(userID)).Returns(cart).InOrder().OccursOnce();
userServiceMock.ValidateUser(userName, password);
shoppingCartServiceMock.LoadCart(userID);
Mock.Assert(userServiceMock);
Mock.Assert(shoppingCartServiceMock);
}
CopyVB
<TestMethod()>
Public Sub ShouldAssertInOrderForDifferentInstancesInTestMethodScope()
Dim userName As String = "Bob"
Dim password As String = "Password"
Dim userID As Integer = 5
Dim cart As IList(Of String) = {"Foo", "Bar"}
Dim userServiceMock = Mock.Create(Of IUserValidationService)()
Dim shoppingCartServiceMock = Mock.Create(Of IShoppingCartService)()
Mock.Arrange(Function() userServiceMock.ValidateUser(userName, password)).Returns(userID).InOrder().OccursOnce()
Mock.Arrange(Function() shoppingCartServiceMock.LoadCart(userID)).Returns(cart).InOrder().OccursOnce()
userServiceMock.ValidateUser(userName, password)
shoppingCartServiceMock.LoadCart(userID)
Mock.Assert(userServiceMock)
Mock.Assert(shoppingCartServiceMock)
End Sub
In the arrange phase we have defined that the ValidateUser call should be made only once and before the LoadCart service call.
The LoadCart call should also occur only once and should follow the ValidateUser service call.
We act and then assert our expectations.
Note |
|---|
Refer to this topic to learn more about asserting occurance. The example also uses the Returns option in order to ignore the actual call and return a custom value. |
Benefits of Using Arrange Act Assert
See Also