0

I Have Batch apex which will send emails when a article was published yesterday(we have scheduled to run daily). I have written testclass for it,but iam getting only 6% coverage.Please help me in getting max coverage. below is the batch and test class. Test class:

@isTest(SeeAllData=false)
public class Publishedarticaltest {

public static testMethod void testPublishedarticaltest() {

    Account Acc = new Account(
    Name = 'TestAccount3',
    RecordTypeId = Schema.SObjectType.Account.getRecordTypeInfosByName().get('Organization').getRecordTypeId());
    insert Acc;

    Contact con = new Contact(FirstName = 'Test1',Lastname = 'McTesty',AccountId =Acc.Id,Email ='test8@gmail.com');
    insert con;

    Profile p = [Select Id from Profile where name = 'xyz'];

    User u = new User(
    Username = 'PortalHomePageCtrlTest@test.com',
    ProfileId = p.Id,
    Alias = 'test123',
    Email = 'PortalHomePageCtrlTest@test.com',
    EmailEncodingKey = 'UTF-8',
    LastName = 'McTesty',
    TimeZoneSidKey = 'America/Los_Angeles',
    LocaleSidKey = 'en_US',
    LanguageLocaleKey = 'en_US',
    contactid =con.id
    );
    insert u;

    Project__c p1 = new Project__c();
    p1.Name='Cessation';
    p1.Full_Project_Name__c='health';
    insert p1;

    HVC__kav kv = new HVC__kav();
    kv.Title='test';
    kv.urlname='testurl';
    kv.Alert_All_Portal_Users__c = true;
    kv.Summary= 'test';
    kv.IsVisibleInPkb=true;
    kv.IsVisibleInCsp=true;
    kv.IsVisibleInPrm =true;
    kv.project__c=p1.id;
    kv.language='en_US';
    insert kv;
   HVC__kav k = [Select KnowledgeArticleId from HVC__kav where ID = :kv.Id];

    KbManagement.PublishingService.publishArticle(k.KnowledgeArticleId, true);

    HVC__DataCategorySelection dc= new HVC__DataCategorySelection();
    dc.DataCategoryName='Project_Specific_Contracting_Webinars';
    dc.ParentId=kv.id;
    dc.DataCategoryGroupName='All_HVC_Articles';
    insert dc;

   Test.startTest();
    //Datetime dtBefore24 = System.now().addDays(-1);
   // Date dtBeforeday = dtBefore24.date();
  // Date dtBeforeday = System.now().date();
   // String query='SELECT Id,Title,ArticleNumber,ArticleType,CreatedDate,FirstPublishedDate,LastPublishedDate,OwnerId,Project__r.Name,'+
    //'IsDeleted,IsLatestVersion,IsVisibleInApp,IsVisibleInPkb,IsVisibleInPrm,KnowledgeArticleId,Language,'+
 //   'Project__c,PublishStatus,UrlName,VersionNumber FROM MHVC__kav WHERE PublishStatus=\'Online\' AND language =\'en_US\' AND IsDeleted = false '+
    //'AND IsLatestVersion = true AND Alert_All_Portal_Users__c =true';

     PublishedArticleNotificationBatch pBatch = new PublishedArticleNotificationBatch();

   Database.executeBatch(pBatch,100);

    Test.StopTest();

}    

}

Batch class:

global class PublishedArticleNotificationBatch implements   Database.Batchable<sObject> {

global Database.QueryLocator start(Database.BatchableContext bc) {

    Datetime dtBefore24 = System.now().addDays(-1);
    Date dtBeforeday = dtBefore24.date();
  // Date dtBeforeday = System.now().date();
   String query='SELECT Id,Title,ArticleNumber,ArticleType,CreatedDate,FirstPublishedDate,LastPublishedDate,OwnerId,Project__r.Name,'+
    'IsDeleted,IsLatestVersion,IsVisibleInApp,IsVisibleInPkb,IsVisibleInPrm,KnowledgeArticleId,Language,'+
    'Project__c,PublishStatus,UrlName,VersionNumber FROM HVC__kav WHERE PublishStatus=\'Online\' AND language =\'en_US\' AND IsDeleted = false '+
    'AND IsLatestVersion = true AND Alert_All_Portal_Users__c =true AND DAY_ONLY(LastPublishedDate) =: dtBeforeday';

 return Database.getQueryLocator(query);
  }
 global void execute(Database.BatchableContext BC, list<HVC__kav> scope){
     List<HVC__kav> publishedArticleList = new  List<HVC__kav>();
     for(HVC__kav artcle:scope){
        publishedArticleList.add(artcle); 
     }
     Map<Id,HVC__DataCategorySelection> dataCatMap = new Map<Id,HVC__DataCategorySelection>([SELECT Id,DataCategoryName,ParentId FROM HVC__DataCategorySelection where ParentId in:publishedArticleList]);
     Map<Id,String> catMap = new Map<Id,String>();  

     for(HVC__DataCategorySelection cat:dataCatMap.values()){
        if(catMap.containsKey(cat.ParentId)==false){
            catMap.put(cat.ParentId, cat.DataCategoryName);

        }
     }
     if(!publishedArticleList.isEmpty()){
         string portalProfile = ApplicationLiterals.protalProfile;
         List<string> emailIds =new  List<string>();
         for(User userObj : [select id,name,FirstName,email from user where profile.Name=:portalProfile and isActive=true]){
             emailIds.add(userObj.Email);

         }
         sendMailToContact(emailIds,publishedArticleList,catMap);
     }
}
global void finish(Database.BatchableContext BC){}

public void sendMailToContact(list<string> emailIDs, List<HVC__kav> publishedArticleList, Map<Id,String> catMap){
    List<Messaging.singleEmailMessage> mails = new List<Messaging.singleEmailMessage>();
    List<OrgWideEmailAddress> owaList = [select id, Address from OrgWideEmailAddress where DisplayName like 'HVC'];
    Document LogoDoc = [Select ID from Document where Folder.Name = 'xyz' and DeveloperName = 'xrt' limit 1];
      //______Sending email code goes here________//
    }
 }
}
2

You can use this trick regarding date related part.

Solution 1

Datetime dtBefore24;
if(!Test.isRunningTest()){
    dtBefore24 = System.now().addDays(-1);
}
else{
    dtBefore24 = System.now();
}
Date dtBeforeday = dtBefore24.date();

Solution 2

Manipulate the query as follows:

Datetime dtBefore24 = System.now().addDays(-1);
Date dtBeforeday = dtBefore24.date();

@TestVisible static String otherCondition = ' AND DAY_ONLY(LastPublishedDate) =:' + dtBeforeday;

String query='SELECT Id,Title,ArticleNumber,ArticleType,CreatedDate,FirstPublishedDate,LastPublishedDate,OwnerId,Project__r.Name,'+
'IsDeleted,IsLatestVersion,IsVisibleInApp,IsVisibleInPkb,IsVisibleInPrm,KnowledgeArticleId,Language,'+
'Project__c,PublishStatus,UrlName,VersionNumber FROM HVC__kav WHERE PublishStatus=\'Online\' AND language =\'en_US\' AND IsDeleted = false '+
'AND IsLatestVersion = true AND Alert_All_Portal_Users__c =true' + otherCondition;

Now, from your test assign the otherCondition to blank or whatever you like.

You will get a coverage.

| improve this answer | |
1

In addition to your date issue that @SantanuBoral has addressed so aptly, you have other issues going on in your test class that ideally also need to be corrected as well.

I'd also expect you to create 2 users. An additional user to use for RunAs to so there will be consistency and no issues related to permissions needed to run the batch class or create articles. Also, your test isn't done the way it needs to in order to assert your results.

I'd recommend you utilize the AsyncApexJob class to help you assert that your job has run and the limits class so you can assert that your emails have been sent.

In addition to using a RunAs User, I'd recommend something like the following.

Test.startTest();

// use @SantanuBoral solution for Datetime

PublishedArticleNotificationBatch pBatch = new PublishedArticleNotificationBatch();

ID batchprocessid = Database.executeBatch(pBatch);

AsyncApexJob aaj = [SELECT Id, Status, JobItemsProcessed, TotalJobItems, NumberOfErrors 
                    FROM AsyncApexJob WHERE ID =: batchprocessid ];

integer emI = getEmailInvocations();

integer emLI = getLimitEmailInvocations();

integer dmls = getDMLStatements();

integer Ldmls = getLimitDMLStatements();

integer dmlr = getDMLRows(); // optional 

integer Ldmlr = getLimitDMLRows(); // optional

Database.executeBatch(pBatch,100);

Test.StopTest();


AsyncApexJob aaj2 = [SELECT Id, Status, NumberOfErrors 
                    FROM AsyncApexJob WHERE ID =: batchprocessid ];

System.AssertEquals(aaj2.Status,'Completed');

System.Equals(aaj2.NumberOfErrors,0);

integer emI2 = Limits.getEmailInvocations();

integer emLI2 = Limits.getLimitEmailInvocations();

System.AssertEquals(emLI-emLI2,emI2-emI);

integer dmls2 = Limits.getDMLStatements();

integer Ldmls2 = Limits.getLimitDMLStatements();

System.AssertEquals(Ldmls-Ldmls2,dmls2-dmls);

integer dmlr2 = Limits.getDMLRows(); // optional 

integer Ldmlr2 = Limits.getLimitDMLRows(); // optional

System.AssertEquals(Ldmlr-Ldmlr2,dmlr2-dmlr);  // optional

You should be able to assert the number of emails that were sent from your batch class either as email or as dml since email invocations also count towards dml. The limits are reduced as the invocations increase. You can do the same thing for queries, query pointer rows, and query rows if you need to. Ideally, you would also replace some of the variables in the assertions with fixed values to reflect the results you expect.

I think it very important that a test class include assertions. Without them, all you're doing is covering lines of code, not validating that the code does what you expect it to do. Without assertions, you can easily release code into production that doesn't function correctly if at all.

| improve this answer | |
  • @cramprogdev , Thank you very much for your valuble comments. it is really helpful. – May the Force be with you Jul 24 '16 at 16:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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