function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Kathleen PalmerKathleen Palmer 

Apex trigger 0% code coverage will not deploy in Production.

Hi! I finally got this simple Apex Trigger working in Sandbox:
trigger restrictFileDeletion on ContentDocument (before delete) {
    String profileName=[SELECT id,Name FROM Profile WHERE Id =:UserInfo.getProfileId()].Name; 
       for (ContentDocument cd : Trigger.old){     
        If(profileName=='ALS Community v6'){
            cd.addError('You cannot delete this record!');
        }
    }
}

Then I went to deploy in production and I received this error "Code Coverage Failure The following triggers have 0% code coverage.  Each trigger must have at least 1% code coverage.restrictFileDeletion.

I have read all related threads and Trailhead, and I'm still stuck on how to write a test class to get this to deploy in production. I would be so appreciate of any help to get this working. I was so excited to get this working in Sandbox, now I've wasted hours, and it's still not working in production. Thanks in advance!!
Best Answer chosen by Kathleen Palmer
EldonEldon
Hi Kathleen Palmer ,

Adding to the above answers, a test class make sure your code is working properly as you wanted.
An ideal test class has 3 parts:
  • A data preparation where you create your test data which will only beused in the context for testing and not saved to the DB
  • Calling the function you want to be tested (For apex classes) or the DML operation which invokes the apextrigger
  • Comparison of the expected and the original results
Salesforce requires a test class with a well coverage before deploying to production to make sure your code doesnt break at any point in the production. 

For your trigger you can refer the following test class:
@isTest
public class restrictFileDeletion_Test {
    
    static testMethod void UnsynchAccountOnUpdateTest() {
        Profile profileId = [SELECT Id FROM Profile WHERE Name = 'ALS Community v6' LIMIT 1];
        User usr = new User(LastName = 'TestUser',
                            FirstName='test',
                            Alias = 'testA',
                            Email = 'test.user@asdf.com',
                            Username = 'test.user@asdf.com',
                            ProfileId = profileId.id,
                            TimeZoneSidKey = 'GMT',
                            LanguageLocaleKey = 'en_US',
                            EmailEncodingKey = 'UTF-8',
                            LocaleSidKey = 'en_US'
                           );
        system.runAs(usr){
            //Create Document
            ContentVersion cv = new ContentVersion();
            cv.Title = 'Test Document';
            cv.PathOnClient = 'TestDocument.pdf';
            cv.VersionData = Blob.valueOf('Test Content');
            cv.IsMajorVersion = true;
            Insert cv;
            
            List<ContentDocument> cdList = [SELECT Id, Title, LatestPublishedVersionId FROM ContentDocument];
            
            Test.startTest(); 
            
            try{
                Delete cdList;                    
            }
            catch(Exception e)
            {
                List<ContentDocument> cdList2 = [SELECT Id, Title, LatestPublishedVersionId FROM ContentDocument];            
                String message = e.getMessage();
                Boolean expectedExceptionThrown =  e.getMessage().contains('You cannot delete this record!') ? true : false;
                System.assertEquals(expectedExceptionThrown, true);
                System.assertEquals(1, cdList2.size());
            }
            Test.stopTest();
        }
    }
}

Best Regards
Eldon

All Answers

Yuri AldanovYuri Aldanov
Hi Kathleen.
I have created trigger like this one:
trigger UnsynchAccountOnUpdate on Account (before update) {
     
    Id profileId=userinfo.getProfileId();
    String profileName=[Select Id,Name from Profile where Id=:profileId].Name;

    if(profileName!='APIClient')
    {
		for (Account updatedAccount : Trigger.new) 
        {
			updatedAccount.Synchronized__c = false;
			updatedAccount.SyncFailed__c = false;
			updatedAccount.LastModifiedById__c = updatedAccount.LastModifiedById;
    	}
    }
}
And I have created unit test for this trigger like this:
@isTest
private class test4UnsynchAccountOnUpdateTrigger {

    static testMethod void UnsynchAccountOnUpdateTest() {
    	
    	Account testrec = new Account();
    	testrec.Name = 'Rec1';
    	testrec.BillingStreet = '111 Nova ave.';
    	testrec.Description = 'Fake record 1 for testing';
    	insert testrec;
    	
    	Test.startTest();
    	
        Account testAccount = [select Id, Name, Synchronized__c from Account LIMIT 1];
        testAccount.Name = 'Trigger test';
        update testAccount;
        
        System.assert(testAccount.Synchronized__c == false);
        System.assert(testAccount.SyncFailed__c == false);
        
        Test.stopTest();
    }
}
You just need to create fake record then start test (Test.startTest()), try to update it (update testAccount), and verify the result (System.assert) and stop the test (Test.stopTest()).

 
Jason LariJason Lari
I had a simular problem with understanding what test classes did and how to build them when I first started. A test class is used to test the function of what you built to make sure it does was it was designed to do and does not clash with anything else. With triggers, you usually build a class that creates said object, or makes changes to that object to make the trigger fire based on what you built.

Test data is never saved into the system and you cannot access existing objects in the org unless you use @isTest(SeeAllData=true) which generally you want to avoid if possible (which is not always possible). You see the exmaple that Yuri Aldanov made for you, they created a new account outside of the test, then started the test, made the change to that account which then makes the trigger fire and does what it was built to do. Then they use System.assert to verify that the trigger made the required changes. If not then the test fails. When something in the system changes that makes this trigger no longer work or someone tries to deploy something that conflicts with the trigger making it fail, the System.assert will return as a failure so you know something is wrong and prevent the deployment.

I hope this all helps clear things up a little. It was very confusing for me at first too. It gets even more complicated when you start making test classes for visualforce controllers and so on. GL!
EldonEldon
Hi Kathleen Palmer ,

Adding to the above answers, a test class make sure your code is working properly as you wanted.
An ideal test class has 3 parts:
  • A data preparation where you create your test data which will only beused in the context for testing and not saved to the DB
  • Calling the function you want to be tested (For apex classes) or the DML operation which invokes the apextrigger
  • Comparison of the expected and the original results
Salesforce requires a test class with a well coverage before deploying to production to make sure your code doesnt break at any point in the production. 

For your trigger you can refer the following test class:
@isTest
public class restrictFileDeletion_Test {
    
    static testMethod void UnsynchAccountOnUpdateTest() {
        Profile profileId = [SELECT Id FROM Profile WHERE Name = 'ALS Community v6' LIMIT 1];
        User usr = new User(LastName = 'TestUser',
                            FirstName='test',
                            Alias = 'testA',
                            Email = 'test.user@asdf.com',
                            Username = 'test.user@asdf.com',
                            ProfileId = profileId.id,
                            TimeZoneSidKey = 'GMT',
                            LanguageLocaleKey = 'en_US',
                            EmailEncodingKey = 'UTF-8',
                            LocaleSidKey = 'en_US'
                           );
        system.runAs(usr){
            //Create Document
            ContentVersion cv = new ContentVersion();
            cv.Title = 'Test Document';
            cv.PathOnClient = 'TestDocument.pdf';
            cv.VersionData = Blob.valueOf('Test Content');
            cv.IsMajorVersion = true;
            Insert cv;
            
            List<ContentDocument> cdList = [SELECT Id, Title, LatestPublishedVersionId FROM ContentDocument];
            
            Test.startTest(); 
            
            try{
                Delete cdList;                    
            }
            catch(Exception e)
            {
                List<ContentDocument> cdList2 = [SELECT Id, Title, LatestPublishedVersionId FROM ContentDocument];            
                String message = e.getMessage();
                Boolean expectedExceptionThrown =  e.getMessage().contains('You cannot delete this record!') ? true : false;
                System.assertEquals(expectedExceptionThrown, true);
                System.assertEquals(1, cdList2.size());
            }
            Test.stopTest();
        }
    }
}

Best Regards
Eldon
This was selected as the best answer
Kathleen PalmerKathleen Palmer
Thanks @Eldon, @Jason Lari & @Yuri Aldanov. All super helpful replies, and explained very well. I was able to get my test class working, get my code coverage up and deploy in productions, yay! I really apprecaite you help.
Ajay K DubediAjay K Dubedi
Hi Kathleen,

I have gone through your issue and came up with a solution. 
The thing is that you need to define a different profile name(which will be your profile name) when you are testing.
Please try the updated trigger I have created with the test class for it. Both mentioned below - 
 
//Trigger - 

trigger restrictFileDeletion on ContentDocument (before delete) {    
    Id profileId=userinfo.getProfileId();
    String profileName=[Select Id,Name from Profile where Id=:profileId Limit 1].Name;
    for (ContentDocument cd : Trigger.old){  
        if(Test.isRunningTest()) {
            //Here type your profile in place of "System Administrator"
            If(profileName=='System Administrator') {
                cd.addError('You cannot delete this record!');
            }
        } else {
            If(profileName=='ALS Community v6'){
                cd.addError('You cannot delete this record!');
            }
        }       
    }
}


//Test Class - 

@isTest
public class restrictFileDeletionTest {
    @isTest
    public static void testTrigger() {
        ContentVersion contentVersion = new ContentVersion(
            Title = 'Penguins',
            PathOnClient = 'Penguins.jpg',
            VersionData = Blob.valueOf('Test Content'),
            IsMajorVersion = true
        );
        insert contentVersion;
        
        ContentDocument document = new ContentDocument();
    document = [SELECT Id, Title, LatestPublishedVersionId FROM ContentDocument Limit 1];
        try {
            Test.startTest();
            Database.DeleteResult result = Database.delete(document,false);                   
            System.assert(!result.isSuccess());
            System.assert(result.getErrors().size() > 0);
            System.assertEquals('You cannot delete this record!', result.getErrors()[0].getMessage());
            Test.stopTest(); 
        }
        catch(exception e) {}
    }
}

I hope you find the above solution helpful. If it does, please mark as Best Answer to help others too.

Thanks and Regards,
Ajay Dubedi
www.ajaydubedi.com