AcumaticaERP UnitTestFrameworkGuide
AcumaticaERP UnitTestFrameworkGuide
Contents
Copyright...............................................................................................................................................3
Preparing a Test Instance........................................................................................................................ 4
Test Instance: General Information.................................................................................................................. 4
Test Instance: To Deploy an Instance............................................................................................................... 4
Lesson 1: Creating a Test Project and a Test Class..................................................................................... 6
Test Project and Test Class: General Information............................................................................................6
Test Project and Test Class: Activity 1.1: To Create a Test Project.................................................................. 7
Test Project and Test Class: Activity 1.2: To Create a Test Class....................................................................10
Lesson 2: Creating a Test Method........................................................................................................... 11
Test Method: General Information..................................................................................................................11
Test Method: Activity 2.1: To Create a Test Method Without Parameters..................................................... 14
Test Method: Test Management in Visual Studio........................................................................................... 16
Test Method: Activity 2.2: To Run a Test Method........................................................................................... 16
Test Method: Activity 2.3: To Debug a Test Method....................................................................................... 17
Test Method: Activity 2.4: To Create a Test Method with Parameters........................................................... 19
Test Method: Registration of Services............................................................................................................ 21
Test Method: Activity 2.5: To Register a Service.............................................................................................22
Lesson 3: Correctly Assigning Field Values in Tests.................................................................................. 24
Correct Assignment of Field Values in Tests: General Information............................................................... 24
Correct Assignment of Field Values in Tests: Activity 3.1: To Test the Effect of Changing Field Values...... 24
Lesson 4: Testing the Display of Errors and Warnings.............................................................................. 29
Testing of Errors and Warnings: General Information................................................................................... 29
Testing of Errors and Warnings: Activity 4.1: To Test the Display of Errors and Warnings........................... 30
Copyright | 3
Copyright
No part of this document may be reproduced, copied, or transmitted without the express prior consent of
Acumatica, Inc.
3933 Lake Washington Blvd NE, # 350, Kirkland, WA 98033
Restricted Rights
The product is provided with restricted rights. Use, duplication, or disclosure by the United States Government is
subject to restrictions as set forth in the applicable License and Services Agreement and in subparagraph (c)(1)(ii)
of the Rights in Technical Data and Computer Soware clause at DFARS 252.227-7013 or subparagraphs (c)(1) and
(c)(2) of the Commercial Computer Soware-Restricted Rights at 48 CFR 52.227-19, as applicable.
Disclaimer
Acumatica, Inc. makes no representations or warranties with respect to the contents or use of this document, and
specifically disclaims any express or implied warranties of merchantability or fitness for any particular purpose.
Further, Acumatica, Inc. reserves the right to revise this document and make changes in its content at any time,
without obligation to notify any person or entity of such revisions or changes.
Trademarks
Acumatica is a registered trademark of Acumatica, Inc. HubSpot is a registered trademark of HubSpot, Inc.
Microso Exchange and Microso Exchange Server are registered trademarks of Microso Corporation. All other
product names and services herein are trademarks or service marks of their respective companies.
In this chapter, you will learn how to deploy an Acumatica ERP test instance that contains custom and customized
forms. You can use this instance to complete a training course or test a scenario described in this guide. You can use
this instance to complete the training course.
Learning Objectives
In this chapter, you will learn how to do the following:
• Prepare the environment
• Deploy an Acumatica ERP test instance
Applicable Scenarios
You deploy an Acumatica ERP test instance by using the instructions in this chapter in the following cases:
• You want to test the activities described in this guide.
• You need to complete a training course.
You deploy an Acumatica ERP test instance by using the instructions in this chapter, if you need to complete the
training course.
This activity will walk you through the process of preparing the environment and deploying an Acumatica ERP
instance that you can use to perform the activities of this guide.
Story
Suppose that you want to learn how to create any unit tests provided in the Unit Test Framework Guide. You need
to deploy an Acumatica ERP instance by using the Acumatica ERP Configuration Wizard.
Preparing a Test Instance | 5
Process Overview
You will prepare the environment—that is, install the soware that you need to use Acumatica ERP and to create
customizations for it. Then you will deploy an Acumatica ERP instance with the data for the T280 Testing Business
Logic with the Acumatica Unit Test Framework course.
If you have already installed Acumatica ERP without debugger tools, you should remove
Acumatica ERP and install it again with the Install Debugger Tools check box selected. The
reinstallation of Acumatica ERP does not affect existing Acumatica ERP instances. For details,
see To Install the Acumatica ERP Tools.
As the first step in creating a set of unit tests for an extension library in a customization project, you create a Visual
Studio project and configure it to serve as the test project. For each graph or graph extension to be tested, you
create a separate test class in the test project.
Learning Objectives
In this chapter, you will learn how to do the following:
• Create a project in Visual Studio
• Configure the project to be a test project that uses the xUnit.net library and the Acumatica Unit Test
Framework
• Create the test class that will contain unit tests
Applicable Scenarios
You create and configure a test project each time you need to create unit tests for graphs and graph extensions
implemented in a customization project. You create a test class for each graph or graph extension for which you will
create unit tests.
Test Project and Test Class: Activity 1.1: To Create a Test Project
The following activity will walk you through the process of creating and configuring a test project.
Story
Suppose that you have an extension library implemented in the PhoneRepairShop_Code.csproj Visual
Studio project. You need to create a test project in which you will develop unit tests for graphs and graph
extensions in this extension library. You will use the xUnit.net library and the Acumatica Unit Test Framework in
the unit tests.
Process Overview
In Visual Studio, you will create a test project in the same solution with the extension library that implements the
graphs and graph extensions being tested. You will add the xunit and xunit.runner.visualstudio NuGet
packages to the test project. You will also add the PX.Tests.Unit.dll library and other libraries from the
Acumatica ERP instance to the test project.
System Preparation
As a prerequisite, before you begin creating a test project, make sure that you have performed the Test Instance: To
Deploy an Instance activity.
5. In the Preview Changes dialog box (shown in the following screenshot), click OK. This causes the xunit
package to be installed.
Lesson 1: Creating a Test Project and a Test Class | 9
Step 3: Adding References to the Customization Code and Acumatica ERP Libraries
To add references to the customization project and Acumatica ERP libraries to the
PhoneRepairShop_Code.Tests.csproj project, proceed as follows:
1. Optional: Copy the PX.Tests.Unit.dll file from the UnitTesting subfolder of the Acumatica ERP
installation folder to any folder you choose.
2. Right-click the References item of the PhoneRepairShop_Code.Tests project, and select Add
Reference.
3. On the Browse tab, click Browse.
4. In the PhoneRepairShop\Bin folder, select the following files:
• PX.Common.dll
• PX.Common.Std.dll (this library makes it possible to use graph views in the code)
• PX.Data.BQL.Fluent.dll
• PX.Data.dll
• PX.Objects.dll (this library contains the implementation of the
PX.Objects.IN.InventoryItem class)
5. Select the PX.Tests.Unit.dll file in the folder where you have placed it.
6. Optionally, add references to other DLLs.
7. On the Projects tab, select the PhoneRepairShop_Code project.
Lesson 1: Creating a Test Project and a Test Class | 10
8. Click OK.
Test Project and Test Class: Activity 1.2: To Create a Test Class
The following activity will walk you through the process of creating a test class in the test project that you have
created.
Story
Suppose that you have created and configured the PhoneRepairShop_Code.Tests test project for the
extension library implemented in the PhoneRepairShop_Code.csproj project. You need to create a
class for testing the Repair Services (RS201000) custom form, whose business logic is implemented in the
RSSVRepairServiceMaint class.
Process Overview
In the test project, you create a test class derived from the PX.Tests.Unit.TestBase class. This class is
intended for containing test methods.
System Preparation
Before you begin creating the test class, make sure that you have performed the following prerequisite activities:
1. Test Instance: To Deploy an Instance, to prepare the Acumatica ERP instance
2. Test Project and Test Class: Activity 1.1: To Create a Test Project, to create and configure the
PhoneRepairShop_Code.Tests.csproj test project
using Xunit;
using PX.Data;
using PX.Tests.Unit;
using PhoneRepairShop;
5. Make the RSSVRepairServiceMaintTests class public and derived from TestBase as follows.
In this class, you will create a test method to test the logic of the RSSVRepairServiceMaint graph, as
described in Test Method: Activity 2.1: To Create a Test Method Without Parameters. For more information about
creating test methods, see Lesson 2: Creating a Test Method.
Lesson 2: Creating a Test Method | 11
In a test class, which is intended for testing a graph or graph extension, you will create test methods, each of which
will test a particular functionality. Through the xUnit.net library, which you will use for creating unit tests in the
activities of this guide, you can create test methods without parameters and test methods with parameters. In
addition to the presence or absence of parameters, these kinds of methods differ in the attributes they have and
the number of unit tests they produce.
Learning Objectives
In this chapter, you will learn how to do the following:
• Create test methods without parameters
• Create an instance of the tested graph
• Create and update objects in the graph cache
• Verify that the desired conditions are met for the values present in the method
• Run and debug test methods
• Create test methods with parameters
• Set values for the test parameters
• Create unit tests for graph extensions
Applicable Scenarios
You create a test method if you want to test some business logic of a graph or graph extension.
Development of a Test
A unit test is an automated test written by a soware developer that tests some independent unit of code. A unit
test usually launches some functionality of a soware component and then compares the resulting values with
the expected values. As you develop unit tests, the best practice is to create them according to the standard AAA
pattern:
1. Arrange: You prepare the test's context and assign some values.
2. Act: You launch the functionality of a graph or graph extension.
3. Assert: You check the result.
With the Acumatica Unit Test Framework, you can easily create unit tests according to this process.
In the arrange part, you initialize the context until actions can be correctly executed. To use the Acumatica
Unit Test Framework for this part, you may need to first enable some application features (by using the
Common.UnitTestAccessProvider.EnableFeature<FeatureType> generic method) or initialize
Lesson 2: Creating a Test Method | 12
the required setup DACs (by using the Setup<PXGraph> generic method). Aer that, you create an instance of a
graph (by using the PXGraph.CreateInstance<PXGraph> generic method) and fill its caches.
Some automated tests, typically referred to as integration tests, validate the interaction of multiple independent
components. With Acumatica Unit Test Framework, you can implement these tests and check the interaction of
multiple components within a graph.
Assertions
You can use the methods of the Xunit.Assert class to make assertions in unit tests. For example, the
Assert.True static method verifies that its argument is equal to True, and the Assert.False static method
verifies that its argument is equal to False. The following table lists additional methods of the Xunit.Assert
class that may be useful.
Lesson 2: Creating a Test Method | 13
Method Description
Contains<T>(T expected, IEnumerable<T> Verifies that a collection contains a given object. The
collection) method also throws a ContainsException if the
collection does not contain the object.
DoesNotContain<T>(T expected, IEnumer- Verifies that a collection does not contain a given
able<T> collection) object. The method also throws a DoesNotCon-
tainException if the collection contains the ob-
ject.
Null(object obj) Verifies that the object reference is null and throws a
NullException if the object reference is not null.
NotNull(object obj) Verifies that an object reference is not null, and throws
a NotNullException if the object reference is null.
Method Description
Equal(string expected, string actual) Verifies that the actual and expected strings are
equivalent. The method also throws an EqualEx-
ception if the actual and expected strings are
not equivalent.
Equal<T>(T expected, T actual) Verifies that two objects are equal by using a default
comparer, and throws an EqualException if the
objects are not equal.
Equal<T>(T[] expected, T[] actual) Verifies that two arrays of the unmanaged type T are
equal. The method also throws an EqualException
if the arrays are not equal.
You can use some assertion library instead of the Xunit.Assert class (for example, FluentAssertions).
The following activity will walk you through the process of creating a test method without parameters.
Story
Suppose that you want to make sure that the following behavior of the Repair Services (RS201000) custom form
has not changed: The selection of the Walk-In Service check box and the selection of the Requires Preliminary
Check check box are mutually exclusive. You need to create a test method that changes the state of one check box
and checks the state of the other check box.
Process Overview
To create the test method, you will create a public void method and assign it the [Fact] attribute. In the method,
you will create an instance of the tested graph. In the cache of the graph, you will create a record. In this record, you
will change the values of the fields that indicate the states of the check boxes, update the cache of the graph, and
check that the values of dependent fields have been changed according to the tested logic of the graph.
System Preparation
Before you begin creating the test method, make sure that you have performed the following prerequisite activities:
1. Test Instance: To Deploy an Instance, to prepare the Acumatica ERP instance that you will use
2. Test Project and Test Class: Activity 1.1: To Create a Test Project, to create and configure the
PhoneRepairShop_Code.Tests.csproj test project
Lesson 2: Creating a Test Method | 15
3. Test Project and Test Class: Activity 1.2: To Create a Test Class, to create the
RSSVRepairServiceMaintTests test class
2. By using the following code, assign the [Fact] attribute to the method to specify that this unit test is
called without parameters.
[Fact]
public void PreliminaryCheckAndWalkInServiceFlags_AreOpposite()
4. Now that the RSSVRepairServiceMaint graph is initialized, use the following code to create an
RSSVRepairService object that represents a record in the table of the Repair Services form.
RSSVRepairService repairService =
graph.Caches[typeof(RSSVRepairService)].
Insert(new RSSVRepairService
{
ServiceCD = "Service1",
Description = "Service 1",
WalkInService = true,
PreliminaryCheck = false
}) as RSSVRepairService;
Objects that represent table records are created in the graph cache (PXCache objects). You can address a
specific cache of a graph either by the DAC name (graph.Caches[typeof(<DAC_name>)]) or by the
graph view that contains the DAC objects (graph.<DACView>.Cache).
5. Aer a record is created, determine whether a change of the Walk-In Service check box state leads to a
change of the Requires Preliminary Check check box state. Also, determine whether a change of the
Requires Preliminary Check check box state leads to a change of the Walk-In Service check box. Perform
this checking by adding the following code.
repairService.WalkInService = false;
graph.Caches[typeof(RSSVRepairService)].Update(repairService);
Assert.True(repairService.PreliminaryCheck);
repairService.WalkInService = true;
graph.Caches[typeof(RSSVRepairService)].Update(repairService);
Assert.False(repairService.PreliminaryCheck);
repairService.PreliminaryCheck = false;
graph.Caches[typeof(RSSVRepairService)].Update(repairService);
Lesson 2: Creating a Test Method | 16
Assert.True(repairService.WalkInService);
repairService.PreliminaryCheck = true;
graph.Caches[typeof(RSSVRepairService)].Update(repairService);
Assert.False(repairService.WalkInService);
To walk through the process of running the test method, see Test Method: Activity 2.2: To Run a Test Method. For
details about debugging the test method, see Test Method: Activity 2.3: To Debug a Test Method.
The test methods that you have created appear in the Test Explorer window of Visual Studio, which is shown in the
following screenshot.
For each test method without parameters (see Test Method: Activity 2.1: To Create a Test Method Without
Parameters), a test has been added. For parameterized test methods (see Test Method: Activity 2.4: To Create a Test
Method with Parameters), a test has been added for each set of parameter values that you have specified for the
method.
In the Test Explorer window of Visual Studio, you can select the desired test, test method, or group of test
methods, and you can run (see Test Method: Activity 2.2: To Run a Test Method) or debug (see Test Method: Activity
2.3: To Debug a Test Method) them. You can also get information about the tests' outcomes (whether they have
succeeded or not) and execution time.
The following activity will walk you through the process of running a single test method.
Story
Suppose that you have a test method implemented in a test class. You need to run the test method.
Process Overview
In the Test Explorer window of Visual Studio, you will select a method and run it.
Lesson 2: Creating a Test Method | 17
System Preparation
Before you begin running the test method, make sure that you have performed the following prerequisite activities:
1. Test Instance: To Deploy an Instance, to prepare the Acumatica ERP instance that you will use
2. Test Project and Test Class: Activity 1.1: To Create a Test Project, to create and configure the
PhoneRepairShop_Code.Tests.csproj test project
3. Test Project and Test Class: Activity 1.2: To Create a Test Class, to create the
RSSVRepairServiceMaintTests test class
4. Test Method: Activity 2.1: To Create a Test Method Without Parameters, to create the
PreliminaryCheckAndWalkInServiceFlags_AreOpposite test method
If your code contains test methods other than the one created in Test Method: Activity 2.1: To Create
a Test Method Without Parameters, or if you have already run the existing test method before, the
number of items mentioned in the following instruction may differ.
Do the following to run the method created in Test Method: Activity 2.1: To Create a Test Method Without Parameters:
1. In Visual Studio, select the Test > Test Explorer menu item. The Test Explorer window opens, which
currently displays no tests.
2. Click Run All Tests In View. The solution is built, and one test for the
PreliminaryCheckAndWalkInServiceFlags_AreOpposite test method appears in the Test
Explorer window (shown in the following screenshot) and is run.
The following activity will walk you through the process of debugging a test method.
Lesson 2: Creating a Test Method | 18
Story
Suppose that you have a test method implemented in a test class. You need to debug the test method in order to
detect possible errors.
Process Overview
In Visual Studio, you will set breakpoints both in the code being tested and in the test method, launch the
debugging for the test method from the Test Explorer window, and check that the values of the fields are as
expected.
System Preparation
Before you begin debugging the test method, make sure that you have performed the following prerequisite
activities:
1. Test Instance: To Deploy an Instance, to prepare the Acumatica ERP instance that you will use
2. Test Project and Test Class: Activity 1.1: To Create a Test Project, to create and configure the
PhoneRepairShop_Code.Tests.csproj test project
3. Test Project and Test Class: Activity 1.2: To Create a Test Class, to create the
RSSVRepairServiceMaintTests test class
4. Test Method: Activity 2.1: To Create a Test Method Without Parameters, to create the
PreliminaryCheckAndWalkInServiceFlags_AreOpposite test method
repairService.WalkInService = false;
row.PreliminaryCheck = true;
e) method of the RSSVRepairServiceMaint class is launched. The execution pauses at the breakpoint
in the RSSVRepairServiceMaint.cs file, which signifies that the extension library and unit test match
each other.
11.Continue debugging (you can press F5 for this). The debugging process continues until it completes
successfully.
The following activity will walk you through the process of creating a test method with parameters.
Story
Suppose that you want to make sure that the following behavior of the customized Stock Items (IN202500) form
has not changed: The selection of the Repair Item check box causes the Repair Item Type drop-down list to
be available, and the clearing of the Repair Item check box causes the Repair Item Type drop-down list to be
unavailable. You need to create a test method that selects or clears the Repair Item check box and checks whether
the Repair Item Type drop-down list is available or unavailable, respectively.
Process Overview
To create the test method, you will create a public void method with one Boolean parameter. You will assign the
method the [Theory] attribute and two [InlineData] attributes, each of which has the possible values of the
method parameter (true and false). In the method, you will create an instance of the tested graph. In the cache of
the graph, you will create a record. For this record, by using the GetExtension generic method, you will retrieve
the extension, which contains custom fields. Depending on the method parameter, you will change the state of
the check box, update the cache of the graph, and make sure that the availability of the drop-down list has been
changed according to the tested logic of the graph.
System Preparation
Before you begin creating the test method, do the following:
1. Make sure that you have performed the Test Instance: To Deploy an Instance prerequisite activity to prepare
the Acumatica ERP instance that you will use.
2. Make sure that you have performed the Test Project and Test Class: Activity 1.1: To Create a Test Project
prerequisite activity to create and configure the PhoneRepairShop_Code.Tests.csproj test
project.
3. Create the InventoryItemMaintTests test class. For an example that shows how to create a test class,
see Test Project and Test Class: Activity 1.2: To Create a Test Class.
Before you begin creating the test method, create the InventoryItemMaintTests test class. For an example
that shows how to create a test class, see Test Project and Test Class: Activity 1.2: To Create a Test Class.
[Theory]
public void RepairItemTypeEnabled_WhenRepairItemSelected
4. Add two [InlineData] attributes, which provide two values for the enabled parameter, as follows.
[Theory]
[InlineData(true)]
[InlineData(false)]
public void RepairItemTypeEnabled_WhenRepairItemSelected
(bool enabled)
InventoryItem item =
(InventoryItem)graph.Caches[typeof(InventoryItem)].Insert(
new InventoryItem
{
InventoryCD = "Item1",
Descr = "Item 1"
});
4. Select (or clear) the Repair Item check box by using the needed value of the enabled parameter, and
make sure that the Repair Item Type drop-down list is available (or, respectively, unavailable) by adding
the following code.
itemExt.UsrRepairItem = enabled;
graph.Caches[typeof(InventoryItem)].Update(item);
PXFieldState fieldState =
((PXFieldState)graph.Caches[typeof(InventoryItem)].GetStateExt<
InventoryItemExt.usrRepairItemType>(item));
Assert.True(enabled == fieldState.Enabled);
Lesson 2: Creating a Test Method | 21
A call of the PXCache.Update method for the InventoryItem object updates both the
object and its extension.
As a result of the actions you have performed in this activity, the InventoryItemMaintTests.cs file contains
the following code.
using Xunit;
using PX.Data;
using PX.Tests.Unit;
using PX.Objects.IN;
namespace PhoneRepairShop_Code.Tests
{
public class InventoryItemMaintTests : TestBase
{
[Theory]
[InlineData(true)]
[InlineData(false)]
public void RepairItemTypeEnabled_WhenRepairItemSelected
(bool enabled)
{
var graph = PXGraph.CreateInstance<InventoryItemMaint>();
InventoryItem item =
(InventoryItem)graph.Caches[typeof(InventoryItem)].Insert(
new InventoryItem
{
InventoryCD = "Item1",
Descr = "Item 1"
});
itemExt.UsrRepairItem = enabled;
graph.Caches[typeof(InventoryItem)].Update(item);
PXFieldState fieldState =
((PXFieldState)graph.Caches[typeof(InventoryItem)].GetStateExt<
InventoryItemExt.usrRepairItemType>(item));
Assert.True(enabled == fieldState.Enabled);
}
}
}
In some circumstances, running this test method may fail. To learn the actions that you must perform to make this
test method successful, see Test Method: Activity 2.5: To Register a Service.
Acumatica uses the dependency injection technique to design soware. With this technique, an object (a client)
receives other objects (services) that it depends on; in this context, these services are called dependencies. Each
Lesson 2: Creating a Test Method | 22
of these services must be registered: For each needed interface, you must specify the service that implements this
interface.
This soware design pattern is used to decouple code components and make them easier to extend and test.
For more information about dependency injection, see https://docs.microsoft.com/en-us/dotnet/core/extensions/
dependency-injection.
In unit tests, mock services are used instead of real complex objects. These mock services are simplified services
that mimic real ones.
To register a service, you need to override the TestBase.RegisterServices method and make calls to the
Autofac.ContainerBuilder.RegisterType generic method.
You can also define your own service, register it, and use it in a PX.Tests.Unit.TestBase-derived class as
described in Dependency Injection.
The following activity will walk you through the process of registering a mock service in a test class.
Story
Suppose that running a test method leads to the generation of the
Autofac.Core.Registration.ComponentNotRegisteredException exception. When this exception
occurs, the error message specifies which component (interface) is not registered. You need to register the service
that implements the specified interface.
Process Overview
To get rid of the exception, you will add the use of the Autofac library and override the
TestBase.RegisterServices method in the test class. In the overridden RegisterServices method,
you will register the needed service that implements the interface specified in the exception message.
System Preparation
Before you begin implementing the registration of a service, do the following:
1. Make sure that you have performed the Test Instance: To Deploy an Instance prerequisite activity to prepare
the Acumatica ERP instance that you will use.
Lesson 2: Creating a Test Method | 23
2. Make sure that you have performed the Test Project and Test Class: Activity 1.1: To Create a Test Project
prerequisite activity to create and configure the PhoneRepairShop_Code.Tests.csproj test
project.
3. Create the InventoryItemMaintTests test class. For an example that shows how to create a test class,
see Test Project and Test Class: Activity 1.2: To Create a Test Class.
4. Make sure that you have performed the Test Method: Activity 2.4: To Create a Test Method with Parameters
prerequisite activity to create the RepairItemTypeEnabled_WhenRepairItemSelected test
method.
5. Run the RepairItemTypeEnabled_WhenRepairItemSelected test method.
using Autofac;
using PX.Objects.CM.Extensions;
Aer the service is registered, run the tests for the RepairItemTypeEnabled_WhenRepairItemSelected
test method, which had failed previously. Make sure that the tests succeed.
Lesson 3: Correctly Assigning Field Values in Tests | 24
When you create unit tests for graphs or graph extensions, you may encounter various difficulties related to
assigning field values: If you assign field values in the wrong places, the results of the code execution may be
unpredictable.
Learning Objectives
In this chapter, you will learn how to do the following:
• Specify the values of key and non-key fields when an object is created or updated
• Use the default field values when an object is created
Applicable Scenarios
In unit tests, you specify field values every time you create or update DAC objects in the cache.
Correct Assignment of Field Values in Tests: Activity 3.1: To Test the Effect of
Changing Field Values
The following activity will walk you through the process of creating a method that tests complicated business logic
involving the assignment of field values.
Story
Suppose that you want to make sure that the following behavior of the Services and Prices (RS203000) form has
not changed: If changes are made to the state of the Required or Default check box (or both check boxes) of a row,
Lesson 3: Correctly Assigning Field Values in Tests | 25
these changes affect the states of these check boxes in other rows. Also, you want to make sure that the prices are
calculated correctly.
You need to create a test method. In this method, you need to create at least three repair items of different types
and a labor item, configure them, and make sure that the fields that correspond to the Required and Default check
boxes have the correct states and that the boxes with prices have the correct values.
Process Overview
You will create a test method without parameters for the Services and Prices (RS203000) form. In this method,
you will create an instance of the tested graph, RSSVRepairPriceMaint. In the cache of the graph, you
will create the necessary objects by using the PXCache.Insert method, and configure them by using the
PXCache.Update method. Then you will use the methods of the Assert class to verify that the necessary
conditions for the values of the objects' fields are met.
System Preparation
Before you begin creating the test method, do the following:
1. Make sure that you have performed the Test Instance: To Deploy an Instance prerequisite activity to prepare
the Acumatica ERP instance that you will use.
2. Make sure that you have performed the Test Project and Test Class: Activity 1.1: To Create a Test Project
prerequisite activity to create and configure the PhoneRepairShop_Code.Tests.csproj test
project.
3. Create the RSSVRepairPriceMaintTests test class. For an example that shows how to create a test
class, see Test Project and Test Class: Activity 1.2: To Create a Test Class.
Before you begin creating the test method, create the RSSVRepairPriceMaintTests test class. For an
example that shows how to create a test class, see Test Project and Test Class: Activity 1.2: To Create a Test Class.
Step 1: Creating a Test Method for the Services and Prices Form
In this step, you will create a test method for the Services and Prices (RS203000) form. (For basic information on the
creation of a test method without parameters, see Test Method: General Information.) Do the following:
1. In the RSSVRepairPriceMaintTests class, create a public void method, and name it
TestServicesAndPricesForm.
2. Specify the [Fact] attribute for the method to indicate that this unit test is called without parameters.
2. Create a device to repair (an RSSVDevice object) and a service for repairing the device (an
RSSVRepairService object) by adding the following code. You will use the IDs of the device and the
service to create an RSSVRepairPrice object.
graph.Caches[typeof(RSSVDevice)].Insert(new RSSVDevice
{
DeviceCD = "Device1"
});
graph.Caches[typeof(RSSVRepairService)].Insert(new
Lesson 3: Correctly Assigning Field Values in Tests | 26
RSSVRepairService
{
ServiceCD = "Service1"
});
When you are creating an object, you need to specify values for its key fields. If you do not
specify a value for an object's key field during the creation of the object, you cannot change
the field value later.
3. Create an RSSVRepairPrice object that will contain details about the repair service as follows.
RSSVRepairPrice repairPrice =
(RSSVRepairPrice)graph.Caches[typeof(RSSVRepairPrice)].
Insert(new RSSVRepairPrice());
You could have specified the values for the key fields, DeviceID and ServiceID, but you did not because
the DeviceID and ServiceID fields are assigned their values from the Current properties of the
RSSVDevice and RSSVRepairService types.
4. Create three repair items—two of the Battery type, and one of the BackCover type—by using the
following code.
InventoryItem battery2 =
(InventoryItem)graph.Caches[typeof(InventoryItem)].Insert(new
InventoryItem
{
InventoryCD = "Battery2"
});
graph.Caches[typeof(InventoryItemCurySettings)].Insert(new
InventoryItemCurySettings
{
InventoryID = battery2.InventoryID,
CuryID = "USD"
});
InventoryItemExt batteryExt2 =
battery2.GetExtension<InventoryItemExt>();
batteryExt2.UsrRepairItem = true;
batteryExt2.UsrRepairItemType = RepairItemTypeConstants.Battery;
graph.Caches[typeof(InventoryItem)].Update(battery2);
Lesson 3: Correctly Assigning Field Values in Tests | 27
InventoryItem backCover1 =
(InventoryItem)graph.Caches[typeof(InventoryItem)].Insert(new
InventoryItem
{
InventoryCD = "BackCover1"
});
graph.Caches[typeof(InventoryItemCurySettings)].Insert(new
InventoryItemCurySettings
{
InventoryID = backCover1.InventoryID,
CuryID = "USD"
});
InventoryItemExt backCoverExt1 =
backCover1.GetExtension<InventoryItemExt>();
backCoverExt1.UsrRepairItem = true;
backCoverExt1.UsrRepairItemType = RepairItemTypeConstants.BackCover;
graph.Caches[typeof(InventoryItem)].Update(backCover1);
This code adds an InventoryItemCurySettings object to the cache for each created repair item to
give users the ability to specify the price of the repair items.
This code also demonstrates the right order of instructions when you are implementing unit tests: You insert
a new object into the cache by calling the PXCache.Insert method, and then you change non-key fields
of the object and call the PXCache.Update method.
5. Create a non-stock item that represents the work to be done by adding the following code.
6. Create repair items based on the stock items, and configure them by adding the following code.
This code creates three repair items: one back cover, and two batteries.
7. Add the following code to check the values of the Required and IsDefault fields.
// 2nd battery is not required -> 1st battery is also not required
Assert.False(repairItemBattery1.Required);
// 2nd batt is used by default -> 1st batt is not used by default
Assert.False(repairItemBattery1.IsDefault);
// The back cover's Required and Default fields are not affected
Assert.True(repairItemBackCover1.Required);
Assert.True(repairItemBackCover1.IsDefault);
// 2nd battery is not required -> 1st battery is also not required
Assert.False(repairItemBattery1.Required);
// 2nd batt is used by default -> 1st batt is not used by default
Assert.False(repairItemBattery1.IsDefault);
// The back cover's Required and Default fields are not affected
Assert.True(repairItemBackCover1.Required);
Assert.True(repairItemBackCover1.IsDefault);
2. Add the following code to ensure that the prices are calculated correctly.
The logic of a graph can include the displaying of errors and warnings on the UI. In a test method, you can verify
that certain actions cause an error or warning to be displayed.
Learning Objectives
In this chapter, you will learn how to do the following:
• Test the logic of a graph that has a setup DAC
• Test whether a proper error is attached to a field
• Test whether a proper warning is attached to a field
• Clear the cache of errors
• Find the proper DAC object in the cache
Applicable Scenarios
In unit tests, you can check whether an appropriate warning or error is attached to a box when the entered value
does not fit the logic of the form.
In your code, aer you have tested the displaying of an error or warning, you clear the cache of errors and warnings
with the PXCache.Clear method.
The attaching of an error or warning to a field may be the result of an action that generates an exception or cancels
the assignment of a value. In this case, the cache may contain different DAC objects before and aer performing
such an action. To pick the proper DAC object for testing, you call the PXCache.Locate method and pass an
object of that DAC type having the correct values of the key fields.
Testing of Errors and Warnings: Activity 4.1: To Test the Display of Errors and
Warnings
The following activity will walk you through the process of creating a method that tests the display of warning and
error messages.
Story
Suppose that you want to make sure that the following behavior of the Repair Work Orders (RS301000) form has
not changed:
• When a new work order is initialized, the system copies to it the repair items and labor items of the
RSSVRepairPrice object that has the same DeviceID and ServiceID values as the work order being
initialized.
• Negative values of labor quantities are prohibited.
• The values of labor quantities are not permitted to be less than the minimum values.
• In work orders for which the priority is Low, repair services that are marked as requiring preliminary checks
are prohibited.
You need to create a test method. In this method, you need to initialize the settings of the graph.
Process Overview
You will create a test method without parameters for the Repair Work Orders (RS301000) form. In this method, you
will initialize the settings of the tested graph RSSVWorkOrderEntry by calling the Setup<> generic method.
Then you will create an instance of the RSSVWorkOrderEntry graph. In the cache of the graph, you will create
the necessary objects and configure them. You will assign to the fields values that are not allowed by the business
logic of the graph and ensure that the appropriate warnings or errors appear in the UI; you will do this by calling the
PXCache.GetStateExt method.
System Preparation
Before you begin creating the test method, do the following:
1. Make sure that you have performed the Test Instance: To Deploy an Instance prerequisite activity to prepare
the Acumatica ERP instance that you will use.
2. Make sure that you have performed the Test Project and Test Class: Activity 1.1: To Create a Test Project
prerequisite activity to create and configure the PhoneRepairShop_Code.Tests.csproj test
project.
3. Create the RSSVWorkOrderEntryTests test class. For an example that shows how to create a test class,
see Test Project and Test Class: Activity 1.2: To Create a Test Class.
Before you begin creating the test method, create the RSSVWorkOrderEntryTests test class. For an example
that shows how to create a test class, see Test Project and Test Class: Activity 1.2: To Create a Test Class.
Lesson 4: Testing the Display of Errors and Warnings | 31
Step 1: Creating a Test Method for the Repair Work Orders Form
In this step, you will create a test method for the Repair Work Orders (RS301000) form. (For basic information on the
creation of a test method without parameters, see Test Method: General Information.) Do the following:
1. In the RSSVWorkOrderEntryTests class, create a public void method, and name it
TestRepairWorkOrdersForm.
2. Specify the [Fact] attribute for the method to indicate that this unit test is called without parameters.
3. Initialize the settings for the RSSVWorkOrderEntry graph by adding the following code.
Setup<RSSVWorkOrderEntry>(new RSSVSetup());
The RSSVSetup DAC contains settings for the RSSVWorkOrderEntry graph. The call of the Setup<>
generic method is mandatory because it initializes an RSSVSetup object.
4. Create an instance of the RSSVWorkOrderEntry graph as follows.
RSSVRepairService repairService =
(RSSVRepairService)graph.Caches[typeof(RSSVRepairService)].
Insert(new RSSVRepairService
{
ServiceCD = "Service1"
});
RSSVRepairService repairService2 =
(RSSVRepairService)graph.Caches[typeof(RSSVRepairService)].
Insert(new RSSVRepairService
{
ServiceCD = "Service2"
});
2. Create an RSSVRepairPrice object, and initialize it with the RSSVDevice object and the main
RSSVRepairService object. You do this by adding the following code.
graph.Caches[typeof(RSSVRepairPrice)].Insert(new RSSVRepairPrice
{
DeviceID = device.DeviceID,
ServiceID = repairService.ServiceID
});
3. Add the following code to create two stock items and one non-stock item, and to make the two stock items
repair items.
InventoryItem battery1 =
Lesson 4: Testing the Display of Errors and Warnings | 32
(InventoryItem)graph.Caches[typeof(InventoryItem)].Insert(new
InventoryItem
{
InventoryCD = "Battery1"
});
InventoryItemExt batteryExt1 =
battery1.GetExtension<InventoryItemExt>();
batteryExt1.UsrRepairItem = true;
batteryExt1.UsrRepairItemType = RepairItemTypeConstants.Battery;
graph.Caches[typeof(InventoryItem)].Update(battery1);
InventoryItem backCover1 =
(InventoryItem)graph.Caches[typeof(InventoryItem)].Insert(new
InventoryItem
{
InventoryCD = "BackCover1"
});
InventoryItemExt backCoverExt1 =
backCover1.GetExtension<InventoryItemExt>();
backCoverExt1.UsrRepairItem = true;
backCoverExt1.UsrRepairItemType =
RepairItemTypeConstants.BackCover;
graph.Caches[typeof(InventoryItem)].Update(backCover1);
InventoryItem work1 =
(InventoryItem)graph.Caches[typeof(InventoryItem)].Insert(new
InventoryItem
{
InventoryCD = "Work1",
StkItem = false
});
4. Create two repair items based on the two stock items as follows.
RSSVRepairItem repairItemBackCover1 =
(RSSVRepairItem)graph.Caches[typeof(RSSVRepairItem)].Insert(
new RSSVRepairItem
{
DeviceID = device.DeviceID,
ServiceID = repairService.ServiceID
});
repairItemBackCover1.InventoryID = backCover1.InventoryID;
repairItemBackCover1.Required = true;
repairItemBackCover1.BasePrice = 10;
repairItemBackCover1.IsDefault = true;
repairItemBackCover1.RepairItemType =
backCoverExt1.UsrRepairItemType;
graph.Caches[typeof(RSSVRepairItem)].Update(repairItemBackCover1);
RSSVRepairItem repairItemBattery1 =
(RSSVRepairItem)graph.Caches[typeof(RSSVRepairItem)].Insert(
new RSSVRepairItem
{
DeviceID = device.DeviceID,
ServiceID = repairService.ServiceID
});
repairItemBattery1.InventoryID = battery1.InventoryID;
Lesson 4: Testing the Display of Errors and Warnings | 33
repairItemBattery1.Required = true;
repairItemBattery1.BasePrice = 20;
repairItemBattery1.IsDefault = true;
repairItemBattery1.RepairItemType = batteryExt1.UsrRepairItemType;
graph.Caches[typeof(RSSVRepairItem)].Update(repairItemBattery1);
5. Create an RSSVLabor object based on the non-stock item by using the following code.
6. Create a work order with the same DeviceID and ServiceID values as those specified for the
RSSVRepairPrice object, which was created in Instruction 2. To do this, add the following code.
Assert.Equal(2, graph.RepairItems.Select().Count);
Assert.Single(graph.Labor.Select());
2. As the second test, add the following code to ensure that the changing of the ServiceID field of the work
order does not affect the RepairItems and Labor views.
workOrder.ServiceID = repairService2.ServiceID;
graph.Caches[typeof(RSSVWorkOrder)].Update(workOrder);
Assert.Equal(2, graph.RepairItems.Select().Count);
Assert.Single(graph.Labor.Select());
workOrder.ServiceID = repairService.ServiceID;
graph.Caches[typeof(RSSVWorkOrder)].Update(workOrder);
4. Obtain the RSSVWorkOrderLabor object (the value of its Quantity field must be 3), and try to assign a
negative value to its Quantity field by using the following code. An error message must be attached to the
Quantity field instead.
Lesson 4: Testing the Display of Errors and Warnings | 34
In the code, the PXCache.Clear method is called to clear the cache of the generated error.
5. By using the following code, assign to the Quantity field of the RSSVWorkOrderLabor object a value
that is less than the value of the corresponding RSSVLabor.Quantity field. Then make sure that the
following result is achieved: A warning message is attached to the RSSVWorkOrderLabor.Quantity
field, and the field is assigned the value of the corresponding RSSVLabor.Quantity field.
woLabor.Quantity = 1;
graph.Caches[typeof(RSSVWorkOrderLabor)].Update(woLabor);
woLabor = (RSSVWorkOrderLabor)graph.
Caches[typeof(RSSVWorkOrderLabor)].Locate(woLabor);
fieldState = (PXFieldState)graph.
Caches[typeof(RSSVWorkOrderLabor)].
GetStateExt<RSSVWorkOrderLabor.quantity>(woLabor);
Assert.Equal(PhoneRepairShop.Messages.QuantityToSmall,
fieldState.Error);
Assert.Equal(PXErrorLevel.Warning, fieldState.ErrorLevel);
Assert.Equal(3, woLabor.Quantity);
In the code, you use the PXCache.Locate method to obtain the proper RSSVWorkOrderLabor object
from the cache to check the presence and text of the warning.
6. By using the following code, configure the second repair service repairService2 to require a
preliminary check, and assign it to the work order. The code also sets the priority of the work order to Low
and makes sure that an error message is attached to the Priority field of the work order; this error
message informs the user that the priority of the work order is too low.
repairService2.PreliminaryCheck = true;
graph.Caches[typeof(RSSVRepairService)].Update(repairService2);
workOrder.ServiceID = repairService2.ServiceID;
workOrder.Priority = WorkOrderPriorityConstants.Low;
graph.Caches[typeof(RSSVWorkOrder)].Update(workOrder);
workOrder = (RSSVWorkOrder)graph.Caches[typeof(RSSVWorkOrder)].
Locate(workOrder);
fieldState = (PXFieldState)graph.Caches[typeof(RSSVWorkOrder)].
GetStateExt<RSSVWorkOrder.priority>(workOrder);
Assert.Equal(PhoneRepairShop.Messages.PriorityTooLow, fieldState.Error);
Assert.Equal(PXErrorLevel.Error, fieldState.ErrorLevel);
7. Run the test method you have created, and make sure that it succeeds.