Back to Blog

Microsoft Dynamics 365 for Finance and Operations Type Provider Tests – Part 3: Testing Personas

Post by |

In this third and final post in this series on type provider tests for Dynamics 365 for Finance and Operations (D365FO), we will look at testing personas. Within law firms using LexisOne, which is built on D365FO, this would range from IT administrators to end-user fee earners and anything in between.

The main reason you would test against particular personas is to ensure that the appropriate security authorisation for specific roles is applied and functioning effectively. The D365FO unit test framework provides the functionality to do this.

Persona-specific testing will build on the type provider test you have already created in the previous posts of this series. The business scenario we are testing is the creation of a project. To test the security authorisation of this process, you will create three personas.

The test class will define personas, using these as identifiers that are assigned a number of roles. During a test you can then switch the user to use different personas. The tests don’t switch to a different user, rather the code is run in the context of a different set of roles.

First, you should define the personas you are going to use in your tests. Currently in your test class declaration you have the following code:

[SysTestCaseDataDependencyAttribute("GBSI"), SysCodeGenAttribute()] class CreateProjectTPTest extends SysTestCase

The class that contains the functionality to change the user’s permissions as part of the D365FO unit test framework is called the SysTestSecurityContext. You therefore need to define this as part of the class attribute that is going to set up the personas.

SysTestTargetAttribute(classstr(SysTestSecurityContext), UtilElementType::Class)

You then need to add the personas as a class attribute. To do this for each persona, you need to define three properties.

  • An identifier/name for the persona
  • A list of roles that the persona will contain
  • Whether the persona is the default role

First, you will create a persona that has access to create a project. Call this ValidCreateProjectUser and give it the role of Project manager. You will also set this as the default test persona. When defining the roles for the persona, you need to use the Name property of the security role in the application explorer. So, for Project manager’ this will be ProjProjectManageras shown below.

Create a Persona

Once you have the role name you can use the roleStr function, ensuring that Visual Studio will generate a compile-time error if the role specified is not there or if the role name has been spelt incorrectly. You have to add one role - the TestEssentialsRole role - to all personas as it is required for some of the unit test framework. So your persona will be defined as below:

SysTestSecurity('ValidCreateProjectUser', [ roleStr(ProjProjectManager), roleStr(TestEssentialsRole) ], true)

You combine the SysTestSecurity attribute with the SysTestTargetAttribute to create the attribute to add to your test.

[SysTestTargetAttribute(classstr(SysTestSecurityContext), UtilElementType::Class),
SysTestSecurity('ValidCreateProjectUser', [ roleStr(ProjProjectManager), roleStr(TestEssentialsRole) ], true)]
[SysTestCaseDataDependencyAttribute("GBSI"), SysCodeGenAttribute()]
class CreateProjectTPTest extends SysTestCase

The SysTestSecurityContext provides the functionality to define which persona you want to use in your tests. The first method will run the test as the admin user. To do this you can use setAdminPersona:

using(var projUserScope = SysTestSecurityContext::setAdminPersona())
{
//Add your test code here
}

To switch to the new persona you have defined in the class attributes, you can use the setCurrentPersona method, passing in the identifier we defined in the attribute. To switch to the ValidCreateProjectUser you can use the following code:

using(var projUserScope = SysTestSecurityContext::setCurrentPersona('ValidCreateProjectUser'))
{
//Add your test code here
}

Next, define another persona that doesn’t have access to the Create new project button, such as the Project supervisor role. The application explorer will show you that the role name is ProjProjectSupervisor, and for the purposes of the tests, you should give it a persona identifier of NotValidCreateProjectUser.

SysTestSecurity('NotValidCreateProjectUser', [ roleStr(ProjProjectSupervisor), roleStr(TestEssentialsRole) ], true)

You should then add this alongside the other persona in the class attribute, so the class attribute is as below:

[SysTestTargetAttribute(classstr(SysTestSecurityContext), UtilElementType::Class),
SysTestSecurity('ValidCreateProjectUser', [ roleStr(ProjProjectSupervisor), roleStr(TestEssentialsRole) ], true),
SysTestSecurity('NotValidCreateProjectUser', [ roleStr(ProjProjectSupervisor), roleStr(TestEssentialsRole) ], false)]
[SysTestCaseDataDependencyAttribute("GBSI"), SysCodeGenAttribute()]
class CreateProjectTPTest extends SysTestCase

Please note if you define multiple personas, only one of the personas should be set to true as the default persona.

You can now create three tests, starting with one that will run as admin and one that will run as the ValidCreateProjectUser persona. These tests will contain similar code and will successfully create the project. The third test will be run as the NotValidCreateProjectUser persona. This test will need to check the properties on the button to observe that both the enabled and visible properties are set to false. The code below implements this logic:

using ProjectListFormAdaptor = Microsoft.Dynamics.AX.TypeProviders.FormAdaptors.FormAdaptorTypeProvider@[formStr(ProjProjectsListPage)];
using ProjTableCreateAdaptor = Microsoft.Dynamics.AX.TypeProviders.FormAdaptors.FormAdaptorTypeProvider@[formStr(ProjTableCreate)];

[SysTestCaseDataDependencyAttribute("GBSI"), SysCodeGenAttribute()]
class CreateProjectTPTest extends SysTestCase {
[SysTestMethodAttribute]
public void ProjProjectsListPage_CreateProject_NotAllowedUser() {
using(var projUserScope = SysTestSecurityContext::setCurrentPersona('NotValidCreateProjectUser') {
using (ProjectListFormAdaptor projectListPage = ProjectListFormAdaptor::open()) {
boolean newButtonEnabled = projectListPage.ProjectNewButton().enabled();
boolean newButtonVisible = projectListPage.ProjectNewButton().visible();
this.assertFalse(newButtonEnabled);
this.assertFalse(newButtonVisible);
}
}
}
}

The code for the two tests that successfully create the project would be as below. Note that the test method names have been changed to define the expected test outcome as per the naming convention described in the second post.

Admin user test

using ProjectListFormAdaptor = Microsoft.Dynamics.AX.TypeProviders.FormAdaptors.FormAdaptorTypeProvider@[formStr(ProjProjectsListPage)];

using ProjTableCreateAdaptor = Microsoft.Dynamics.AX.TypeProviders.FormAdaptors.FormAdaptorTypeProvider@[formStr(ProjTableCreate)];

using ProjTableAdaptor = Microsoft.Dynamics.AX.TypeProviders.FormAdaptors.FormAdaptorTypeProvider@[formStr(ProjTable)];

[SysTestCaseDataDependencyAttribute("GBSI"), SysCodeGenAttribute()]
class CreateProjectTPTest extends SysTestCase {
[SysTestMethodAttribute]
public void ProjProjectsListPage_CreateProject_AdminUser() {
using(var projUserScope = SysTestSecurityContext::setAdminPersona()) {
using (ProjectListFormAdaptor projectListPage = ProjectListFormAdaptor::open()) {
projectListPage.ProjectNewButton().click();
using (ProjTableCreateAdaptor projTableCreate = ProjTableCreateAdaptor::attach()) {

//Set the Project name
projTableCreate.Name().setValue("TP Coded Project");
//Set the Project group
projTableCreate.ProjTable_ProjGroupId().setValue("TM_WIP");
//Set the Project contract ID
projTableCreate.ProjInvoiceId().setValue("00000002");
projTableCreate.OKCommandButton().click();
using(ProjTableAdaptor projTable = ProjTableAdaptor::attach()) {
projTable.close();
}
}
}
}
}
}

Valid user test

using ProjectListFormAdaptor = Microsoft.Dynamics.AX.TypeProviders.FormAdaptors.FormAdaptorTypeProvider@[formStr(ProjProjectsListPage)];

using ProjTableCreateAdaptor = Microsoft.Dynamics.AX.TypeProviders.FormAdaptors.FormAdaptorTypeProvider@[formStr(ProjTableCreate)];

using ProjTableAdaptor = Microsoft.Dynamics.AX.TypeProviders.FormAdaptors.FormAdaptorTypeProvider@[formStr(ProjTable)];

Whilst these scenarios have been defined as three separate tests, it is possible to change the persona during the same test if you need to test different roles during a process. On running these tests, they should pass successfully and you should see green ticks in the Visual Studio Test Explorer.

Hopefully this blog has demonstrated an effective and efficient way to test code and security permissions, using the D365FO type provider tests, for different roles within a law firm or other organisation.

About the Author:


Chris Lowe is a Technical Architect for LexisNexis working on the Dynamics 365 for Finance and Operations version of the LexisOne ERP solution. He is based at the LexisNexis office in Leeds, UK, where he has been working on Dynamics 365 for Finance and Operations for approximately the last 2 years. Prior to this he was working on the Dynamics AX 2012 version of LexisOne. Before his move to Dynamics AX related technologies he worked on .Net browser based applications in both the legal and banking industries. He has 20 years’ experience working in IT software development.

| See all our contributors
Back to Blog