KB Article T849007
Visible to All Users

How to unit test Action's enabled/disabled state based on user permissions

Test Scenario
We have a Controller that enables/disables an Action depending on user permissions. Our task is to test the UpdateSetTaskActionState method to ensure that it correctly disables/enables the SetTask Action based on the user Write permissions for the Status and Priority properties of selected DemoTask objects. If a user can't write any of these properties, the Action is disabled. Otherwise, it's enabled.

C#
public class TaskActionsController : ViewController { private SingleChoiceAction setTaskAction; public TaskActionsController() setTaskAction = new SingleChoiceAction(this, "SetTaskAction", PredefinedCategory.Edit); } public SingleChoiceAction SetTaskAction { get => setTaskAction; } protected override void OnActivated() { base.OnActivated(); View.SelectionChanged += new EventHandler(View_SelectionChanged); UpdateSetTaskActionState(); } void View_SelectionChanged(object sender, EventArgs e) { UpdateSetTaskActionState(); } public void UpdateSetTaskActionState() { bool isGranted = true; foreach (object selectedObject in View.SelectedObjects) { bool isPriorityGranted = SecuritySystem.IsGranted(new PermissionRequest(ObjectSpace, typeof(DemoTask), SecurityOperations.Write, selectedObject, nameof(DemoTask.Priority))); bool isStatusGranted = SecuritySystem.IsGranted(new PermissionRequest(ObjectSpace, typeof(DemoTask), SecurityOperations.Write, selectedObject, nameof(DemoTask.Status))); if (!isPriorityGranted || !isStatusGranted) { isGranted = false; } } SetTaskAction.Enabled.SetItemValue("SecurityAllowance", isGranted); } }
Visual Basic
Public Class TaskActionsController Inherits ViewController Private _setTaskAction As SingleChoiceAction Protected Overrides Sub OnActivated() MyBase.OnActivated() AddHandler View.SelectionChanged, AddressOf View_SelectionChanged UpdateSetTaskActionState() End Sub Private Sub View_SelectionChanged(ByVal sender As Object, ByVal e As EventArgs) UpdateSetTaskActionState() End Sub Public Sub UpdateSetTaskActionState() Dim isGranted As Boolean = True For Each selectedObject As Object In View.SelectedObjects Dim isPriorityGranted As Boolean = SecuritySystem.IsGranted(New PermissionRequest(ObjectSpace, GetType(DemoTask), SecurityOperations.Write, selectedObject, "Priority")) Dim isStatusGranted As Boolean = SecuritySystem.IsGranted(New PermissionRequest(ObjectSpace, GetType(DemoTask), SecurityOperations.Write, selectedObject, "Status")) If Not isPriorityGranted OrElse Not isStatusGranted Then isGranted = False End If Next selectedObject SetTaskAction.Enabled.SetItemValue("SecurityAllowance", isGranted) End Sub Public Sub New() _setTaskAction = New SingleChoiceAction(Me, "SetTaskAction", PredefinedCategory.Edit) End Sub Public ReadOnly Property SetTaskAction() As SingleChoiceAction Get Return _setTaskAction End Get End Property End Class

Unit Test Implementation
Let's create a test fixture class to implement our test:

C#
using DevExpress.ExpressApp; using DevExpress.ExpressApp.Security; using MySolution.Module.Controllers; using Moq; using NUnit.Framework; using System; namespace MySolution.Tests { [TestFixture] public class SetTaskActionStateTest { } }
Visual Basic
Imports DevExpress.ExpressApp Imports DevExpress.ExpressApp.Security Imports MySolution.Module.Controllers Imports Moq Imports NUnit.Framework <TestFixture()> Public Class SetTaskActionStateTest End Class

Our business logic depends on selected objects and the result the SecuritySystem.IsGranted method returns. The SetTask Action's Enabled state does not depend on what objects are selected. We can use any object types and mock the SecuritySystem.IsGranted method. In this article, we will use strings rather than DemoTask objects to illustrate the power of mocks. However, you can create real DemoTask objects and change the SecuritySystem.IsGranted method mock implementation to use these objects. You can find an example of how to use real DemoTask objects in the How to unit test that object property changes via Actions were successfully committed article.

First, we need a view with selected objects. Let's use the following method in our test class that will create it:

C#
private View PrepareView(string[] selectedObjects) { var mockView = new Mock<View>(/*isRoot:*/true); mockView.Setup(v => v.SelectedObjects).Returns(selectedObjects); return mockView.Object; }
Visual Basic
Private Function PrepareView(ByVal selectedObjects As String()) As View Dim mockView = New Mock(Of View)(True) mockView.Setup(Function(v) v.SelectedObjects).Returns(selectedObjects) Return mockView.Object End Function

In this method, we mock an XAF view and the passed array of strings will be used as selected objects in the view.

Then, we need to mock how the XAF Security System checks user permissions before each test and reset the XAF Security System after each test. Let's use the following methods to do this:

C#
[SetUp] public void Setup() { var securityMock = new Mock<ISecurityStrategyBase>(); Func<PermissionRequest, bool> permissionFunc = r => (string)r.TargetObject == "Granted"; var requestSecurityMock = securityMock.As<IRequestSecurity>(); requestSecurityMock.Setup(s => s.IsGranted(CreatePermissionMatcher("Priority"))).Returns(permissionFunc); requestSecurityMock.Setup(s => s.IsGranted(CreatePermissionMatcher("Status"))).Returns(permissionFunc); SecuritySystem.SetInstance(securityMock.Object); } [TearDown] public void TearDown() { SecuritySystem.SetInstance(null); } PermissionRequest CreatePermissionMatcher(string name) { return Match.Create<PermissionRequest>(s => s.MemberName == name); }
Visual Basic
<SetUp> Public Sub Setup() Dim securityMock = New Mock(Of ISecurityStrategyBase)() Dim permissionFunc As Func(Of PermissionRequest, Boolean) = Function(r) CStr(r.TargetObject) = "Granted" Dim requestSecurityMock = securityMock.[As](Of IRequestSecurity)() requestSecurityMock.Setup(Function(s) s.IsGranted(CreatePermissionMatcher("Priority"))).Returns(permissionFunc) requestSecurityMock.Setup(Function(s) s.IsGranted(CreatePermissionMatcher("Status"))).Returns(permissionFunc) SecuritySystem.SetInstance(securityMock.Object) End Sub <TearDown> Public Sub TearDown() SecuritySystem.SetInstance(Nothing) End Sub Private Function CreatePermissionMatcher(ByVal name As String) As PermissionRequest Return Match.Create(Of PermissionRequest)(Function(s) s.MemberName = name) End Function

In the Setup method, we specify that a user can write the Priority and Status properties if a current object equals "Granted". Otherwise, a user can't.

Now, we can write our test. Its implementation will be the follows:

C#
[Test] [TestCase(new[] { "Granted", "Denied" }, false)] [TestCase(new[] { "Granted", "Granted" }, true)] public void TaskTest(string[] selectedObjects, bool allowed) { TaskActionsController controller = new TaskActionsController(); controller.SetView(PrepareView(selectedObjects)); controller.UpdateSetTaskActionState(); Assert.That(allowed, Is.EqualTo(controller.SetTaskAction.Enabled["SecurityAllowance"])); }
Visual Basic
<Test> <TestCase({"Granted", "Denied"}, False)> <TestCase({"Granted", "Granted"}, True)> Public Sub TaskTest(ByVal selectedObjects As String(), ByVal allowed As Boolean) Dim controller As TaskActionsController = New TaskActionsController() controller.SetView(PrepareView(selectedObjects)) controller.UpdateSetTaskActionState() Assert.That(allowed, [Is].EqualTo(controller.SetTaskAction.Enabled("SecurityAllowance"))) End Sub

Here, we provide two test cases that are a list of selected objects and the expected enabled/disabled state of the SetTask Action, create our Controller and provide it with a view, then call the tested method and check the result.

See Also
This series contains the following articles:

  1. How to write unit tests for XAF Actions, Controllers, and other custom UI logic
  2. How to unit test Action's enabled/disabled state based on user permissions (current)
  3. How to unit test whether object property changes via Actions were successfully committed
  4. How to unit test object queries by criteria and Detail View creation
  5. How to unit test event handlers in Controllers
  6. How to unit test New Action's custom business logic based on parent and nested Views
  7. How to unit test Action's enabled/disabled state based on target criteria and selection dependency types in List View
  8. How to unit test Action's enabled/disabled state based on target criteria and selection dependency types in Detail View
  9. How to unit test localized strings from CaptionHelper (Approach 1)
  10. How to unit test localized strings from CaptionHelper (Approach 2)
  11. How to unit test custom logic in XAF/XPO business classes

Disclaimer: The information provided on DevExpress.com and affiliated web properties (including the DevExpress Support Center) is provided "as is" without warranty of any kind. Developer Express Inc disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.

Confidential Information: Developer Express Inc does not wish to receive, will not act to procure, nor will it solicit, confidential or proprietary materials and information from you through the DevExpress Support Center or its web properties. Any and all materials or information divulged during chats, email communications, online discussions, Support Center tickets, or made available to Developer Express Inc in any manner will be deemed NOT to be confidential by Developer Express Inc. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.