Test Scenario
This case is similar to the one described in the How to unit test Action's enabled/disabled state based on target criteria and selection dependency types in List View article. The difference is that we need to ensure that an Action is correctly enabled/disabled in a Detail View.
Unit Test Implementation
Let's create a test similar to the one described in the How to unit test Action's enabled/disabled state based on target criteria and selection dependency types in List View article, but for a Detail View. We need to change it to create a DetailView instance that requires a single object and mock the IObjectSpace.Contains method for the reason described in the How to unit test object queries by criteria and Detail View creation article.
C#[Test]
[TestCase(Priority.High, true)]
[TestCase(Priority.Low, false)]
public void ActionsInDetailViewTest(Priority priority, bool result) {
ActionsCriteriaViewController actionsCriteriaViewController = new ActionsCriteriaViewController();
ViewController testedController = new ViewController();
SimpleAction testedAction = new SimpleAction(testedController, "High Priority", string.Empty);
testedAction.TargetObjectsCriteria = "Priority = 2";
DemoTask task = new DemoTask(Session.DefaultSession);
task.Priority = priority;
var objectSpaceMock = new Mock<IObjectSpace>();
objectSpaceMock.Setup(os => os.Contains(It.IsAny<object>())).Returns(true);
objectSpaceMock.Setup(os => os.GetEvaluatorContextDescriptor(typeof(DemoTask))).Returns(new EvaluatorContextDescriptorDefault(typeof(DemoTask)));
var applicationMock = new Mock<XafApplication>();
Frame frame = new Frame(applicationMock.Object, TemplateContext.View, actionsCriteriaViewController, testedController);
frame.SetView(new DetailView(objectSpaceMock.Object, task, applicationMock.Object, true));
Assert.AreEqual(result, testedAction.Enabled.ResultValue);
}
Visual Basic<Test>
<TestCase(Priority.High, True)>
<TestCase(Priority.Low, False)>
Public Sub ActionsInDetailViewTest(ByVal priority As Priority, ByVal result As Boolean)
Dim actionsCriteriaViewController As ActionsCriteriaViewController = New ActionsCriteriaViewController()
Dim testedController As ViewController = New ViewController()
Dim testedAction As SimpleAction = New SimpleAction(testedController, "High Priority", String.Empty)
testedAction.TargetObjectsCriteria = "Priority = 2"
Dim task As DemoTask = New DemoTask(Session.DefaultSession)
task.Priority = priority
Dim objectSpaceMock = New Mock(Of IObjectSpace)()
objectSpaceMock.Setup(Function(os) os.Contains(It.IsAny(Of Object)())).Returns(True)
objectSpaceMock.Setup(Function(os) os.GetEvaluatorContextDescriptor(GetType(DemoTask))).Returns(New EvaluatorContextDescriptorDefault(GetType(DemoTask)))
Dim applicationMock = New Mock(Of XafApplication)()
Dim frame As Frame = New Frame(applicationMock.Object, TemplateContext.View, actionsCriteriaViewController, testedController)
frame.SetView(New DetailView(objectSpaceMock.Object, task, applicationMock.Object, True))
Assert.AreEqual(result, testedAction.Enabled.ResultValue)
End Sub
However, the [TestCase(Priority.High, true)]
case will fail because the Action is disabled. From the How to unit test Action's enabled/disabled state based on target criteria and selection dependency types in List View article, we know that an Action is disabled by its target criteria in the ActionsCriteriaViewController.UpdateAction method. Let's put a breakpoint in it. The interesting part is:
C#protected virtual void UpdateAction(ActionBase action, string criteria) {
if(action.Active && (action.Enabled || action.Enabled.Contains(EnabledByCriteriaKey))) {
bool enable = true;
if(IsActionForUpdate(action) && (action.SelectionContext != null)) {
IList selectedObjects = action.SelectionContext.SelectedObjects;
if(selectedObjects == null || selectedObjects.Count == 0) {
enable = false;
}
else {
// ...
}
action.Enabled.SetItemValue(EnabledByCriteriaKey, enable);
}
}
SelectionContext
is our DetailView now and its SelectedObjects property returns an empty list of objects. The DetailView.SelectedObjects property implementation is:
C#public override IList SelectedObjects {
get {
if(CurrentObject != null) {
return new Object[] { CurrentObject };
}
else {
return new Object[] { };
}
}
}
The Detail View CurrentObject is null. This property is implemented as follows:
C#public override object CurrentObject {
get { return currentObject; }
set {
if(currentObject != value) {
// ...
Guard.CheckObjectFromObjectSpace(ObjectSpace, value);
if(OnQueryCanChangeCurrentObject()) {
UnsubscribeFromObject(currentObject);
currentObject = ObjectSpace.GetObject(value);
// ...
}
}
}
}
Let's put a breakpoint into the property setter and re-run the test in debug mode. We will see that the ObjectSpace.GetObject method returns nothing since we didn't mock it. Let's do this.
C#objectSpaceMock.Setup(os => os.GetObject(It.IsAny<object>())).Returns<object>(obj => obj);
Visual BasicobjectSpaceMock.Setup(Function(os) os.GetObject(It.IsAny(Of Object)())).Returns(Of Object)(Function(obj) obj)
Now, everything works and the entire test code is:
C#[Test]
[TestCase(Priority.High, true)]
[TestCase(Priority.Low, false)]
public void ActionsInDetailViewTest(Priority priority, bool result) {
ActionsCriteriaViewController actionsCriteriaViewController = new ActionsCriteriaViewController();
ViewController testedController = new ViewController();
SimpleAction testedAction = new SimpleAction(testedController, "High Priority", string.Empty);
testedAction.TargetObjectsCriteria = "Priority = 2";
DemoTask task = new DemoTask(Session.DefaultSession);
task.Priority = priority;
var objectSpaceMock = new Mock<IObjectSpace>();
objectSpaceMock.Setup(os => os.Contains(It.IsAny<object>())).Returns(true);
objectSpaceMock.Setup(os => os.GetObject(It.IsAny<object>())).Returns<object>(obj => obj);
objectSpaceMock.Setup(os => os.GetEvaluatorContextDescriptor(typeof(DemoTask))).Returns(new EvaluatorContextDescriptorDefault(typeof(DemoTask)));
var applicationMock = new Mock<XafApplication>();
Frame frame = new Frame(applicationMock.Object, TemplateContext.View, actionsCriteriaViewController, testedController);
frame.SetView(new DetailView(objectSpaceMock.Object, task, applicationMock.Object, true));
Assert.AreEqual(result, testedAction.Enabled.ResultValue);
}
Visual Basic<Test>
<TestCase(Priority.High, True)>
<TestCase(Priority.Low, False)>
Public Sub ActionsInDetailViewTest(ByVal priority As Priority, ByVal result As Boolean)
Dim actionsCriteriaViewController As ActionsCriteriaViewController = New ActionsCriteriaViewController()
Dim testedController As ViewController = New ViewController()
Dim testedAction As SimpleAction = New SimpleAction(testedController, "High Priority", String.Empty)
testedAction.TargetObjectsCriteria = "Priority = 2"
Dim task As DemoTask = New DemoTask(Session.DefaultSession)
task.Priority = priority
Dim objectSpaceMock = New Mock(Of IObjectSpace)()
objectSpaceMock.Setup(Function(os) os.Contains(It.IsAny(Of Object)())).Returns(True)
objectSpaceMock.Setup(Function(os) os.GetObject(It.IsAny(Of Object)())).Returns(Of Object)(Function(obj) obj)
objectSpaceMock.Setup(Function(os) os.GetEvaluatorContextDescriptor(GetType(DemoTask))).Returns(New EvaluatorContextDescriptorDefault(GetType(DemoTask)))
Dim applicationMock = New Mock(Of XafApplication)()
Dim frame As Frame = New Frame(applicationMock.Object, TemplateContext.View, actionsCriteriaViewController, testedController)
frame.SetView(New DetailView(objectSpaceMock.Object, task, applicationMock.Object, True))
Assert.AreEqual(result, testedAction.Enabled.ResultValue)
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
- 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 (current)
- 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