0

I've written Apex classes but this is my first time written a test class. I've read a number of sources and watch videos but I don't grasp the foundation to get a test to successfully cover my code.

Here is my Apex class that works in my full sandbox:

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Reference Code for creating records  
//https://salesforce.stackexchange.com/questions/127889/how-to-automatically-create-a-new-record-in-another-object
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

global class MasterInventoryETL implements Schedulable {
    global void execute(SchedulableContext sc){
        List<Stock_Entry__c > Stock_E = [
            SELECT Aisle__c,Item__c,Last_Record__c,Section__c,Shelf__c,Units_in_Stock__c,units_entry__c,
            Warehouse_name__c,Account_item_owner__c,Effective_Start_Date__c,Effective_End_Date__c,
            Status__c,Stock_Location__c,Transaction_Entry__c,Transaction_Number__c,Virtual_Bin_Designation__c,
            Master_Allocation__c,P_O__c,Shipping_ID__c
            FROM Stock_Entry__c 
            WHERE last_record__c = true 
        ];
        
        List<Master_Inventory__c > snewt = new List <Master_Inventory__c>(); 
        
        
        for( Stock_Entry__c se :Stock_E){
            
            Master_Inventory__c snew = new Master_Inventory__c (
                units_entry__c = se.units_entry__c ,
                Units_in_Stock__c = se.Units_in_Stock__c,
                warehouse_name__c = se.warehouse_name__c ,
                Aisle__c = se.Aisle__c,
                Section__c = se.section__c,
                Shelf__c = se.Shelf__c,
                Status__c = se.Status__c,
                Item__c = se.Item__c,
                Account_item_owner__c =se.Account_item_owner__c,
                Effective_Start_Date__c = se.Effective_Start_Date__c,
                Effective_End_Date__c = se.Effective_End_Date__c,
                Master_Allocation__c = se.Master_Allocation__c,
                P_O__c = se.P_O__c,
                Shipping_ID__c = se.Shipping_ID__c,
                Stock_Location__c = se.Stock_Location__c,
                Transaction_Entry__c = se.Transaction_Entry__c,
                Transaction_Number__c = se.Transaction_Number__c,
                Virtual_Bin_Designation__c = se.Virtual_Bin_Designation__c,
                Power_of_One__c = 1
                
            );
            
            snewt.add(snew);
            
        }
        
        Insert snewt;
    }
    
}

Here is my test class, I have 3 tests using different sources I've read and none work:

@isTest(SeeAllData=TRUE)
Public class MasterInventoryETL_test{
    public static String CRON_EXP = '0 0 1 * * ? ';
  
   @isTest static void test1()
    {
        Stock_Entry__c s = [SELECT Id,pallet_location__c,item__c,aisle__c,shelf__c,
        Virtual_Bin_Designation__c, section__c,status__c, units_Entry__c
        FROM Stock_Entry__c WHERE Virtual_Bin_Designation__c LIKE '%Test%' Limit 1]; 
        System.assert(s != null);        
        // Create a test stock entry item based on the queried record. 
        Stock_Entry__c testStockEntry= s.clone();
        testStockEntry.Virtual_Bin_Designation__c = 'Test Stock';
        insert testStockEntry;

        // Query the test stock entry that was inserted.
        Stock_Entry__c testStockEntry2 = [SELECT Id,pallet_location__c,item__c,aisle__c,shelf__c,
        Virtual_Bin_Designation__c, section__c,status__c, units_Entry__c
        FROM Stock_Entry__c WHERE Virtual_Bin_Designation__c='Test Stock' LIMIT 1];
        System.assert(testStockEntry2 != null);
        
    }

    @isTest static void test2() {
        Account acc = new Account();
        acc.name ='Test';
        acc.RecordTypeID = '012j0000000pirBAAQ';

        insert acc;

        Sourcing_Item__c sitem = new Sourcing_Item__c();
        sitem.name = 'test mitem';
        sitem.Unit_of_measure__c = 'unit';
        sitem.Account_Owner__c = acc.id;
        insert sitem;

        Stock_Entry__c sec = new Stock_Entry__c();
        sec.Virtual_Bin_Designation__c = 'test';
        sec.units_Entry__c = 0;
        sec.item__c = sitem.Id;
        sec.status__c = 'In hand';
        insert sec;

        Test.startTest(); 
        MasterInventoryETL mItest = new MasterInventoryETL();
        mItest.execute(null);
        Test.stopTest(); 

    }

    @isTest static void test3() {
        Account acc = new Account();
        acc.name ='Test';
        acc.RecordTypeID = '012j0000000pirBAAQ';
        insert acc;

        Sourcing_Item__c sitem = new Sourcing_Item__c();
        sitem.name = 'test mitem';
        sitem.Unit_of_measure__c = 'unit';
        sitem.Account_Owner__c = acc.id;
        insert sitem;

        Stock_Entry__c sec = new Stock_Entry__c();
        sec.Virtual_Bin_Designation__c = 'test';
        sec.units_Entry__c = 0;
        sec.item__c = sitem.Id;
        sec.status__c = 'In hand';
        insert sec;

        test.startTest();
        String jobId = System.schedule('MasterInventoryETL',  CRON_EXP,  new MasterInventoryETL()); 
        Test.stopTest(); 

    }


}

Any help would be appreciated. I am making test data to be used in the test method but I'm not even sure what data points I should make, how to make test data or how to confirm I'm creating things properly.

EDIT Current state of testing class:

@isTest
private class MasterInventoryETL_test
{

    @isTest static void test1()
    {
        String CRON_EXP = '0 0 0 15 3 ? *';
        
        // Create your test data
        Account acc = new Account();
        acc.name ='Test';
        acc.RecordTypeID = '012j0000000pirBAAQ';
        insert acc;

        Sourcing_Item__c sitem = new Sourcing_Item__c();
        sitem.name = 'test mitem';
        sitem.Unit_of_measure__c = 'unit';
        sitem.Account_Owner__c = acc.id; 
        insert sitem;

        Stock_Entry__c sec = new Stock_Entry__c();
        sec.Virtual_Bin_Designation__c = 'test';
        sec.units_Entry__c = 0;
        sec.item__c = sitem.Id;
        sec.status__c = 'In hand';
        sec.aisle__c = 'a';
        sec.section__c = 2;
        sec.shelf__c = 'a';
        insert sec;
        
        Test.startTest();

            String jobId = System.schedule('MasterInventoryETLClassTest',  CRON_EXP, new MasterInventoryETL());
            CronTrigger ct = [SELECT Id, CronExpression, TimesTriggered, NextFireTime FROM CronTrigger WHERE id = :jobId];
            System.assertEquals(CRON_EXP, ct.CronExpression);
            System.assertEquals(0, ct.TimesTriggered);

        Test.stopTest();
        // Add assert here to validate result
        List<AsyncApexJob> jobsScheduled = [select Id, ApexClassID, ApexClass.Name, Status, JobType from AsyncApexJob where JobType = 'ScheduledApex'];
        System.assertEquals(1, jobsScheduled.size(), 'expecting one scheduled job');
    }
}
0
1

The pattern of every test fundamentally breaks down to

  1. Create conditions for code to execute.
  2. Execute code.
  3. Validate results.

All of these tests are falling short in at least one of these regards.

test1 doesn't really test anything - it doesn't do (1) or (2), and its assertions for (3) are invalid. The query against Stock_Entry__c will throw a QueryException because there are no records inserted at that point - unit tests cannot see organization data. The two asserts are looking for a condition that will never be true as queries do not return null. More importantly, it has nothing to do with the code under test.

test2 might be functional - the test record it inserts may or may not match the query in the Schedulable class, depending on how Last_Record__c is populated. However, it makes no assertions, and hence does not address (3). It needs to perform a query and write a functional assertion to validate that the Scheduleable class does what it is supposed to.

test3 is basically the same as test2 save that it executes the job asynchronously and correctly uses Test.startTest() and Test.stopTest() to constrain it to execute within test context. Other things being equal, test3 is the preferable form. However, it suffers from the same failings and test2.

The canonical-qa tag on SFSE contains a number of quality resources to teach the principles of writing unit tests.

2
  • Hi David, I reviewed all the content I could on this concept. I put the current state of my test class, I'm still getting no improvement on my code coverage, is it possible that I'm not executing my class? How can I confirm that? Also any criticism on my current test class would be appreciated – Len Cadet Oct 28 '20 at 16:07
  • I suspect that your test data does not match your code's query, as suggested above. – David Reed Oct 28 '20 at 16:43

Not the answer you're looking for? Browse other questions tagged or ask your own question.