Back to T280: Testing Business Logic
Lesson 3: Correctly Assigning Field Values in Tests
When you develop unit tests for Acumatica Framework-based applications, you need make sure that you assign field values in the appropriate places in the code. The topics of this chapter describe how to assign values to key and non-key fields and use default field values in unit tests.
Correct Assignment of Field Values in Tests: General Information
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.
Assignment of Values to Fields
When you are assigning values to DAC fields in unit tests, you need to handle key fields and non-key fields differently. When you create a DAC object in the cache, you use the PXCache.Insert method. As a result, some values (either default values or values you specify) are assigned to the key fields of the DAC object. Aer a DAC object is created, you alter its fields by using the PXCache.Update method. If you alter the key fields in this way, the old DAC object remains unchanged in the cache, but another DAC object with the specified values of the key fields is created or updated in the cache. So to avoid mistakes, you should assign values to the key fields of a DAC object at the stage of creation and should not change them aerward. If a DAC object you are going to create has a key field that is defined with the PXSelector or PXDBDefault attribute, the default value of this key field is taken from the Current property of the DAC specified in the attribute.
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 | 26
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, create the RSSVRepairPriceMaintTests test class. For an example that shows how to create a test class, see 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:
- In the RSSVRepairPriceMaintTests class, create a public void method, and name it TestServicesAndPricesForm.
- Specify the Fact attribute for the method to indicate that this unit test is called without parameters.
Step 2: Creating Necessary Objects To create the objects that are necessary for testing the business logic, do the following:
- In the TestServicesAndPricesForm method, create an instance of the RSSVRepairPriceMaint
graph by adding the following code.
var graph = PXGraph.CreateInstance<RSSVRepairPriceMaint>(); - 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 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.
Lesson 3: Correctly Assigning Field Values in Tests | 27 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. Make sure that you have added the using PX.Objects.IN; directive to the RSSVRepairPriceMaintTests class. 5. Create three repair items—two of the Battery type, and one of the BackCover type—by using the following code.
InventoryItem battery1 = (InventoryItem)graph.
Caches[typeof(InventoryItem)].Insert(new
InventoryItem
{
InventoryCD = "Battery1"
});
graph.Caches[typeof(InventoryItemCurySettings)].Insert(new
InventoryItemCurySettings
{
InventoryID = battery1.InventoryID,
CuryID = "USD"
});
InventoryItemExt batteryExt1 =
battery1.GetExtension<InventoryItemExt>();
batteryExt1.UsrRepairItem = true;
batteryExt1.UsrRepairItemType = RepairItemTypeConstants.Battery;
graph.Caches[typeof(InventoryItem)].Update(battery1);
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);
InventoryItem backCover1 =
(InventoryItem)graph.Caches[typeof(InventoryItem)].Insert(new
InventoryItem
{
InventoryCD = "BackCover1"
});
graph.Caches[typeof(InventoryItemCurySettings)].Insert(new
Lesson 3: Correctly Assigning Field Values in Tests | 28
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. 6. Create a non-stock item that represents the work to be done by adding the following code.
InventoryItem work1 = (InventoryItem)graph.
Caches[typeof(InventoryItem)].Insert(new InventoryItem
{
InventoryCD = "Work1",
StkItem = false
});
7. Create repair items based on the stock items, and configure them by adding the following code.
// Configure the back cover repair item
RSSVRepairItem repairItemBackCover1 =
(RSSVRepairItem)graph.Caches[typeof(RSSVRepairItem)].Insert(
new RSSVRepairItem
{
InventoryID = backCover1.InventoryID,
Required = true,
BasePrice = 10,
IsDefault = true
});
// Configure the first battery repair item
RSSVRepairItem repairItemBattery1 =
(RSSVRepairItem)graph.Caches[typeof(RSSVRepairItem)].Insert(
new RSSVRepairItem
{
InventoryID = battery1.InventoryID
});
repairItemBattery1.Required = true;
repairItemBattery1.BasePrice = 20;
repairItemBattery1.IsDefault = true;
graph.Caches[typeof(RSSVRepairItem)].Update(repairItemBattery1);
// Configure the second battery repair item
RSSVRepairItem repairItemBattery2 =
(RSSVRepairItem)graph.Caches[typeof(RSSVRepairItem)].Insert(
new RSSVRepairItem
{ InventoryID = battery2.InventoryID });
repairItemBattery2.Required = false;
repairItemBattery2.BasePrice = 30;
Lesson 3: Correctly Assigning Field Values in Tests | 29
repairItemBattery2.IsDefault = true;
graph.Caches[typeof(RSSVRepairItem)].Update(repairItemBattery2);
This code creates three repair items: one back cover, and two batteries.
Step 3: Testing the Calculated Values To test the calculated values, do the following:
- 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 battery is used by default -> 1st battery 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); - Add the following code to ensure that the prices are calculated correctly.
RSSVLabor labor = (RSSVLabor)graph.Caches[typeof(RSSVLabor)]. Insert(new RSSVLabor { InventoryID = work1.InventoryID, DefaultPrice = 2, Quantity = 3 }); Assert.Equal(6, labor.ExtPrice); Assert.Equal(66, repairPrice.Price); - Run the created test, and make sure that it succeeds. Lesson 4: Testing the Display of Errors and Warnings | 30