Test Scenario
We have a Controller that changes the Priority or Status property of selected objects when a user invokes an Action. Our task is to test that the Priority or Status property was changed and that the changes are saved, i.e. the IObjectSpace.CommitChanges method was called.
C#public class TaskActionsController : ViewController {
private SingleChoiceAction setTaskAction;
public ChoiceActionItem setPriorityItem;
public ChoiceActionItem setStatusItem;
public TaskActionsController()
setTaskAction = new SingleChoiceAction(this, "SetTaskAction", PredefinedCategory.Edit);
setPriorityItem = new ChoiceActionItem(CaptionHelper.GetMemberCaption(typeof(DemoTask), nameof(DemoTask.Priority)), null);
setTaskAction.Items.Add(setPriorityItem);
FillItemWithEnumValues(setPriorityItem, typeof(Priority));
setStatusItem = new ChoiceActionItem(CaptionHelper.GetMemberCaption(typeof(DemoTask), nameof(DemoTask.Status)), null);
setTaskAction.Items.Add(setStatusItem);
FillItemWithEnumValues(setStatusItem, typeof(TaskStatus));
setTaskAction.Execute += SetTaskAction_Execute;
}
private void FillItemWithEnumValues(ChoiceActionItem parentItem, Type enumType) {
EnumDescriptor ed = new EnumDescriptor(enumType);
foreach (object current in Enum.GetValues(enumType)) {
ChoiceActionItem item = new ChoiceActionItem(ed.GetCaption(current), current);
item.ImageName = ImageLoader.Instance.GetEnumValueImageName(current);
parentItem.Items.Add(item);
}
}
private void SetTaskAction_Execute(object sender, SingleChoiceActionExecuteEventArgs args) {
IObjectSpace objectSpace = View is ListView ? Application.CreateObjectSpace(typeof(DemoTask)) : View.ObjectSpace;
bool shouldCommitChanges = View is ListView || ((View as DetailView)?.ViewEditMode == ViewEditMode.View);
SetupDemoTaskProperties(args.SelectedObjects, args.SelectedChoiceActionItem, objectSpace, shouldCommitChanges);
if (View is ListView) {
View.ObjectSpace.Refresh();
}
}
public void SetupDemoTaskProperties(IList selectedObjects, ChoiceActionItem selectedChoiceActionItem, IObjectSpace objectSpace, bool shouldCommitChanges) {
foreach (object obj in selectedObjects) {
DemoTask objInNewObjectSpace = (DemoTask)objectSpace.GetObject(obj);
if (selectedChoiceActionItem.ParentItem == setPriorityItem) {
objInNewObjectSpace.Priority = (Priority)selectedChoiceActionItem.Data;
}
else if (selectedChoiceActionItem.ParentItem == setStatusItem) {
objInNewObjectSpace.Status = (TaskStatus)selectedChoiceActionItem.Data;
}
}
if (shouldCommitChanges) {
objectSpace.CommitChanges();
}
}
}
Visual BasicPublic Class TaskActionsController
Inherits ViewController
Private _setTaskAction As SingleChoiceAction
Public setPriorityItem As ChoiceActionItem
Public setStatusItem As ChoiceActionItem
Public Sub New()
_setTaskAction = New SingleChoiceAction(Me, "SetTaskAction", PredefinedCategory.Edit)
setPriorityItem = New ChoiceActionItem(CaptionHelper.GetMemberCaption(GetType(DemoTask), NameOf(DemoTask.Priority)), Nothing)
_setTaskAction.Items.Add(setPriorityItem)
FillItemWithEnumValues(setPriorityItem, GetType(Priority))
setStatusItem = New ChoiceActionItem(CaptionHelper.GetMemberCaption(GetType(DemoTask), NameOf(DemoTask.Status)), Nothing)
_setTaskAction.Items.Add(setStatusItem)
FillItemWithEnumValues(setStatusItem, GetType(TaskStatus))
AddHandler _setTaskAction.Execute, AddressOf SetTaskAction_Execute
End Sub
Public ReadOnly Property SetTaskAction() As SingleChoiceAction
Get
Return _setTaskAction
End Get
End Property
Private Sub FillItemWithEnumValues(ByVal parentItem As ChoiceActionItem, ByVal enumType As Type)
Dim ed As New EnumDescriptor(enumType)
For Each current As Object In System.Enum.GetValues(enumType)
Dim item As New ChoiceActionItem(ed.GetCaption(current), current)
item.ImageName = ImageLoader.Instance.GetEnumValueImageName(current)
parentItem.Items.Add(item)
Next current
End Sub
Private Sub SetTaskAction_Execute(ByVal sender As Object, ByVal args As SingleChoiceActionExecuteEventArgs)
Dim objectSpace As IObjectSpace = If(TypeOf View Is ListView, Application.CreateObjectSpace(GetType(DemoTask)), View.ObjectSpace)
Dim shouldCommitChanges As Boolean = TypeOf View Is ListView OrElse (TryCast(View, DetailView)?.ViewEditMode = ViewEditMode.View)
SetupDemoTaskProperties(args.SelectedObjects, args.SelectedChoiceActionItem, objectSpace, shouldCommitChanges)
If TypeOf View Is ListView Then
View.ObjectSpace.Refresh()
End If
End Sub
Public Sub SetupDemoTaskProperties(ByVal selectedObjects As IList, ByVal selectedChoiceActionItem As ChoiceActionItem, ByVal objectSpace As IObjectSpace, ByVal shouldCommitChanges As Boolean)
For Each obj As Object In selectedObjects
Dim objInNewObjectSpace As DemoTask = CType(objectSpace.GetObject(obj), DemoTask)
If selectedChoiceActionItem.ParentItem Is setPriorityItem Then
objInNewObjectSpace.Priority = CType(selectedChoiceActionItem.Data, Priority)
ElseIf selectedChoiceActionItem.ParentItem Is setStatusItem Then
objInNewObjectSpace.Status = CType(selectedChoiceActionItem.Data, TaskStatus)
End If
Next
If shouldCommitChanges Then
objectSpace.CommitChanges()
End If
End Sub
End Class
Unit Test Implementation
Let's create a test fixture class and a test method to implement this:
C#using DevExpress.ExpressApp;
using DevExpress.Xpo;
using MySolution.Module.BusinessObjects;
using MySolution.Module.Controllers;
using Moq;
using NUnit.Framework;
using System.Linq;
namespace MySolution.Tests {
[TestFixture]
public class SetTaskActionExecuteTest {
[Test]
public void SetTaskActionSetPriorityTest() {
}
}
}
Visual BasicImports DevExpress.ExpressApp
Imports DevExpress.Xpo
Imports MainDemo.Module.BusinessObjects
Imports MainDemo.Module.Controllers
Imports Moq
Imports NUnit.Framework
<TestFixture>
Public Class SetTaskActionExecuteTest
<Test>
Public Sub SetTaskActionSetPriorityTest()
End Sub
End Class
First, we need a list of selected objects. Let's create it in our test method:
C#DemoTask[] demoTasks = {
new DemoTask(Session.DefaultSession),
new DemoTask(Session.DefaultSession)
};
Visual BasicDim demoTasks As DemoTask() = {New DemoTask(Session.DefaultSession), New DemoTask(Session.DefaultSession)}
Then, create a TaskActionsController instance and obtain a ChoiceActionItem from it. We will assume that a user clicks this ChoiceActionItem.
C#TaskActionsController controller = new TaskActionsController();
const Priority priority = Priority.High;
var selectedChoiceActionItem = controller.setPriorityItem.Items.Find(priority);
Visual BasicDim controller As TaskActionsController = New TaskActionsController()
Const priority As Priority = Priority.High
Dim selectedChoiceActionItem = controller.setPriorityItem.Items.Find(priority)
All our business logic is implemented in the TaskActionsController SetupDemoTaskProperties method. We need to test only this method. This is XAF responsibility to raise the action Execute event. We don't need to unit test this logic. Use functional tests instead.
The SetupDemoTaskProperties method uses the IObjectSpace GetObject method. Let's mock it:
C#var objectSpaceMock = new Mock<IObjectSpace>();
objectSpaceMock.Setup(o => o.GetObject(It.IsAny<object>())).Returns<object>(obj => obj);
Visual BasicDim objectSpaceMock = New Mock(Of IObjectSpace)()
objectSpaceMock.Setup(Function(o) o.GetObject(It.IsAny(Of Object)())).Returns(Function(obj) obj)
When the IObjectSpace GetObject method is called with an object, we just return this object. That's all and now, we can call the tested SetupDemoTaskProperties method.
C#controller.SetupDemoTaskProperties(demoTasks, selectedChoiceActionItem, objectSpaceMock.Object, true);
Visual Basiccontroller.SetupDemoTaskProperties(demoTasks, selectedChoiceActionItem, objectSpaceMock.Object, True)
Now, make an assertion that all DemoTask objects changed their Priority property and verify that the IObjectSpace CommitChanges method was called:
C#Assert.That(demoTasks.Select(dt => dt.Priority), Is.All.EqualTo(priority)); objectSpaceMock.Verify(o => o.CommitChanges());
Visual BasicAssert.That(demoTasks.Select(Function(dt) dt.Priority), [Is].All.EqualTo(priority))
objectSpaceMock.Verify(Sub(o) o.CommitChanges())
That's it. The full test method code is the following:
C#[Test]
public void SetTaskActionSetPriorityTest() {
DemoTask[] demoTasks = {
new DemoTask(Session.DefaultSession),
new DemoTask(Session.DefaultSession)
};
TaskActionsController controller = new TaskActionsController();
const Priority priority = Priority.High;
var selectedChoiceActionItem = controller.setPriorityItem.Items.Find(priority);
var objectSpaceMock = new Mock<IObjectSpace>();
objectSpaceMock.Setup(o => o.GetObject(It.IsAny<object>())).Returns<object>(obj => obj);
controller.SetupDemoTaskProperties(demoTasks, selectedChoiceActionItem, objectSpaceMock.Object, true);
Assert.That(demoTasks.Select(dt => dt.Priority), Is.All.EqualTo(priority));
objectSpaceMock.Verify(o => o.CommitChanges());
}
Visual Basic<Test>
Public Sub SetTaskActionSetPriorityTest()
Dim demoTasks As DemoTask() = {New DemoTask(Session.DefaultSession), New DemoTask(Session.DefaultSession)}
Dim controller As TaskActionsController = New TaskActionsController()
Const priority As Priority = Priority.High
Dim selectedChoiceActionItem = controller.setPriorityItem.Items.Find(priority)
Dim objectSpaceMock = New Mock(Of IObjectSpace)()
objectSpaceMock.Setup(Function(o) o.GetObject(It.IsAny(Of Object)())).Returns(Function(obj) obj)
controller.SetupDemoTaskProperties(demoTasks, selectedChoiceActionItem, objectSpaceMock.Object, True)
Assert.That(demoTasks.Select(Function(dt) dt.Priority), [Is].All.EqualTo(priority))
objectSpaceMock.Verify(Sub(o) o.CommitChanges())
End Sub
See Also
This series contains the following articles:
- How to write unit tests for XAF Actions, Controllers, and other custom UI logic
- How to unit test Action's enabled/disabled state based on user permissions
- How to unit test whether object property changes via Actions were successfully committed (current)
- How to unit test object queries by criteria and Detail View creation
- How to unit test event handlers in Controllers
- How to unit test New Action's custom business logic based on parent and nested Views
- How to unit test Action's enabled/disabled state based on target criteria and selection dependency types in List View
- How to unit test Action's enabled/disabled state based on target criteria and selection dependency types in Detail View
- How to unit test localized strings from CaptionHelper (Approach 1)
- How to unit test localized strings from CaptionHelper (Approach 2)
- How to unit test custom logic in XAF/XPO business classes