26 Haziran 2022 Pazar

365 F&O - Testing with ATL (Acceptance Test Library)

 365 F&O ATL lets us test developments automatically before publishing and catch up if our development is impressed by another or another development impressed by ours. We don't need any sample data, it creates byself. So dirty data is not a problem for us. After the test is completed it rolls back all test data in SQL Server level.

There are lots of ready to use classes in ATL for testing and if sometimes need to extend they let us extend.

Start by simple one:

[SysTestCaseAutomaticNumberSequences, SysTestTargetAttribute(tableStr(TmpPurchLine), UtilElementType::Table), SysTestGranularityAttribute(SysTestGranularity::Unit)]
class TmpPurchLineTest extends SysTestCase
{

...

 [SysTestMethod]
    public void validateDLvModeAndDlvTermInitiatedPurchLine()
    {
        const VendDlvModeId DlvModeId = 'Air';
        const VendDlvTermId DlvTermId = 'DAP';

        //Arrange
        PurchLine       purchLine;
        TmpPurchLine    tmpPurchLine;

        tmpPurchLine.DlvMode = DlvModeId;
        TmpPurchLine.DlvTerm = DlvTermId;

        //Act
        purchLine.initFromTmpPurchLine(tmpPurchLine);

        //Assert
        this.assertEquals(PurchLine.DlvMode , DlvModeId);
        this.assertEquals(PurchLine.DlvTerm , DlvTermId);

    }

 

We want to initialize values of PurchLine from TmpPurchLine by PurchLine.initFromTmpPurchLine method. Last two red lines validates this.


[SysTestGranularity(SysTestGranularity::Component)]
[SysTestCaseDataDependency('USMF')] //Selects USMF company
[SysTestCaseUseSingleInstance] //run every method in class in a single instance, slower but necessary in some cases, if you don't need, don't use
[SysTestCheckinTest]
public final class PurchPurchaseOrderLineV2EntityTest extends DataEntityTestCase
{

...

    [SysTestMethod]
    public void validateDlvTermAndModeInsertedCorrectyFromEntityToPurchLine()
    {
        // Arrange
        PurchPurchaseOrderLineV2Entity entity;

        ttsbegin;
        AtlEntityPurchaseOrder purchaseOrder = data.purch().purchaseOrders().initDefault()
            .setVendor(data.vend().vendors().default())
            .setInventSiteId(data.invent().sites().default().SiteId)
            .save();

        VendDlvModeId dlvMode = data.sales().modesOfDelivery().findOrCreate('Seafreight').parmModeOfDelivery();
        VendDlvTermId dlvTerm = data.purch().deliveryTerms().findOrCreate('DAP').parmDeliveryTerms();

        ItemId itemId = item.ItemId;
        entity.PurchaseOrderNumber = purchaseOrder.parmPurchId();
        entity.ItemNumber = itemId;
        entity.DlvMode = dlvMode;
        entity.DlvTerm = dlvTerm;
        entity.LineNumber = 1;
        
        // Act
        this.insertEntity(entity);

        // Assert
        purchaseOrder.lines()
           .assertExpected(data.purch().purchaseOrderLines().spec().withDlvMode(DlvMode).withDlvTerm(DlvTerm));
        ttsabort;

In this case we used ATL entity to have data. Used ATL spec. class to ensure we have got expected data.  

If our field(s) missing in Spec, query or entity, we can easly create by wizard:


We can even create a new company (It makes your test class slowly, don't use this unless required):

private void setupDistributorCompany()

    {

     const LegalEntityDataAreaId distributor = 'MTN';

        SysUnitTestData_IntercompanyPlanning::insertCompany(distributor);

 

        changecompany (distributor)

        {

            warehouseInDistr = invent.warehouses().default();

            suppAsVendorInDistr = vendors.createDefault().addRelationToInterCompanyCustomer(distrAsCustomerInSupp);

            normalCustInDist = data.cust().customers().customer002();

        }

    }

 

 

Also we can run form controls too:

 

using SalesTableFormAdaptor = Microsoft.Dynamics.AX.TypeProviders.FormAdaptors.FormAdaptorTypeProvider@[formStr(SalesTable)];
...
public final class PurchLineDlvTermAndModeTest extends AtlPurchaseTestCase
{

...

            using (SalesTableFormAdaptor salesTableForm = SalesTableFormAdaptor::open(salesTable))
            {
                salesTableForm.SalesOrder().activate();
                salesTableForm.buttonCreateDropShipment().click();
                using (PurchCreateFromSalesOrderFormAdaptor purchCreateFromSalesOrder = PurchCreateFromSalesOrderFormAdaptor::attach())
                {
                    purchCreateFromSalesOrder.Grid().moveFirst();
                    purchCreateFromSalesOrder.ChkIncluded().setValue(true);
                    purchCreateFromSalesOrder.SpecifyVendAccount().setValue(vend.vendors().createDefault().record().AccountNum);
                    purchCreateFromSalesOrder.CommandButtonOK().click();
                }
            } 

Create a sales order:

AtlEntitySalesOrder salesOrder = data.sales().salesOrders()
                .createDefault()
                .setCustomer(normalCustInDist)
                .setWarehouse(invent.warehouses().warehouse10())
                .save();

Check more than one spec:

purchaseOrder.lines().withQuantity(OrderedQty1).assertExpected(purchaseOrderLines.spec().withDlvTerm(dlvTerm_DAP));

Check lines more than one:

AtlEntitySalesOrder salesOrder = AtlEntitySalesOrder::find(purchaseOrder.parmInterCompanySalesId());
            //Assert
            salesOrder.lines().assertExpectedLines(
                    salesOrderLines.spec()
                    .withQuantity(OrderedQty1)
                    .withModeOfDelivery(dlvMode_Seafreight)
                    .withDeliveryTerms(dlvTerm_FOB),
                    salesOrderLines.spec()
                    .withQuantity(OrderedQty2)
                    .withModeOfDelivery(dlvMode_Air)
                    .withDeliveryTerms(dlvTerm_DA));

 You can even setup intercompany policies by using objects InterCompanyTradingValueMap, IntercompanyAgreementActionPolicy, InterCompanyEndpointActionPolicy,  ...


You can test by yourself in VS (your opened or added to active project test classes will be come automatically here):