Let's cure the unit test like breathing (Apex trigger edition)

Before

Saleforce has a convention that classes cannot be deployed without 75% or more coverage.

Great convention. But implement unit tests "to get through coverage" There are many cases where various contraindications have been committed.

"What is the unit test for? What is the convention for?"

Discovering such a scene is a series of cures.

It's embarrassing for those who are studying how to write TDD and unit tests properly. I decided to write about how to cure unit tests with the following wishes.

Target execution class

Suppose you have a class like this that starts at after update in the trigger of an object called Dto1__c.

public with sharing class DtoHandler{
    public static void execute(Dto__c dto){
        if(dto.a == 'x'){
            //Process to insert into dto2 object
           insert new Dto2();
        }
    }
}

Before healing

It was like this.

@isTest static void testExecute(){
    Dto__c dto = new Dto(a='x', b='y');
    insert dto;
    update dto:
}

Oh, oh. The coverage goes up because it moves like this with a trigger.

trigger DtoTrigger on Dto__c (after update) {
    DtoHandler.execute(Trigger.New);
    munyamunya();
}

Well, if the unit test doesn't fail, the trigger will run without fail. It seems that we can guarantee that. (collateral?) This is a trigger test, so let's use testDtoTrigger ().

So, if testExecute () is a unit test now, munyamunya () is also running? I mean, what do you know by just updating the data? That's it.

After healing


/*
 *DtoTrigger test method
 */
@isTest static void testDtoTrigger(){
    Test.startTest();
    Dto__c dto = new Dto(a = 'x');
    insert dto;
    //DtoTrigger.Execute trigger update
    //expect: error does not occur when executing update
    dto.a = 'y';
    update dto;
    Test.stopTest();
}
/*
 *test method of execute method
 */
@isTest static void testExecute(){
    Test.startTest();

    //dto generation
    Dto__c dto = new Dto(a='y');

    //a = 'x'Otherwise the record will not be inserted
    DtoHandler.execute(dto);
    Dto2__c dto2_1 = [SELECT Id FROM Dto2__c];
    System.assertEquals(0,dto2_1.size());

    //a = 'x'If dto2 record is inserted
    dto.a = 'y';
    DtoHandler.execute(dto);
    Dto2__c dto2_2 = [SELECT Id FROM Dto2__c];
    System.assertEquals(1,dto2_2.size());

    Test.stopTet();
}

How to cure

--Do not include extra items in the DTO of the unit test. ――Test by a single unit (method unit) instead of the trigger unit. ――By devising comments and writing styles, make it as easy as possible to understand "what test you are doing". --Trigger testing is ultra-minimal (implementation that can be done allows finer test granularity)

Tweet

People who are not used to TDD or want to do TDD but the speed is not good enough. .. Who says If you keep fixing the unfortunate unit test like this, naturally I think it's easier to understand if you write from a unit test. There are good rules, so let's make good use of them.

Recommended Posts

Let's cure the unit test like breathing (Apex trigger edition)
Let's introduce spock framework and write unit tests like test driven
Let's unit test with [rails] Rspec!
What are the side effects? ~ Let's do a small unit test easily ~