3

I've been trying to create a job that while working on my test class I should be able to pass 2 lists and the job work work on those lists but once I deploy my code, it should work using my real data. Since I'm trying to import a list that has a specific LastModifiedDate I create the records using Json. How can I test my job so it runs using test data while I'm in the Sandbox and real data once deployed? This is my class:

public class OpportunityClosedLost {

    public OpportunityClosedLost(List<Opportunity> dummyOppList1, List<Opportunity> dummyOppList2){
        oppListTest1 = dummyOppList1;
        oppListTest2 = dummyOppList2;                                                                       
    }
    private List<Opportunity> oppListTest1,oppListTest2;
    public OpportunityClosedLost(){}
    private List<Opportunity> OppList{get;set;}
    private List<Opportunity> OppList2{get;set;}

    private List<Opportunity> getOppList(){
        if (oppListTest1.isEmpty()) {
            oppListTest1 = ([SELECT Id,OwnerId,Owner.Name, Owner.Email From Opportunity WHERE IsClosed = False AND Is_in_queue__c = False AND
                                        DB_Opportunity_Age__c = 358 ]);
        }
        return oppListTest1;
    }
    private List<Opportunity> getOppList2(){
        if (oppListTest2.isEmpty()) {
            oppListTest2 = ([SELECT Id,OwnerId,Owner.Name, Owner.Email From Opportunity WHERE IsClosed = False AND Is_in_queue__c = False AND
                                        DB_Opportunity_Age__c = 365 ]);
        }
        return oppListTest2;
    }

    public void execute(){

       boolean sent = False;
       System.debug('Size of the list:'+oppListTest1.size());

        List<Messaging.SingleEmailMessage> mails = new List<Messaging.SingleEmailMessage>();

        for (Opportunity o:oppListTest1){

              Messaging.SingleEmailMessage mail= new Messaging.SingleEmailMessage();
              sent = True;
              List<String> sendTo = new List<String>();
              sendTo.add(o.Owner.Email);
              mail.setToAddresses(sendTo);

              mail.setReplyTo('someone');
              mail.setSenderDisplayName('Salesforce Support');


              mail.setSubject('Your Opportunity will be Closed in 7 days');
              String body = '' + o.Owner.Name + ', <br/>';
               body+='This Opportunity link;
               body+=' will change its status to Closed Lost next week due to no activity in 1 year.'+'<br/>';
               body+='If you wish to stop this change please make sure to update the Opportunity or to create an activity within a week.'+'<br/>';
               body+= 'Thank you,'+'<br/>';
               mail.setHtmlBody(body);
               mails.add(mail); 

         }

        for (Opportunity opp2:oppListTest2){

              Messaging.SingleEmailMessage mail= new Messaging.SingleEmailMessage();
              opp2.StageName='Closed Lost';
              opp2.Closed_Lost_Reason__c= 'No Activity';
              List<String> sendTo = new List<String>();
              sendTo.add(opp2.Owner.Email);
              mail.setToAddresses(sendTo);

              mail.setReplyTo('someone');
              mail.setSenderDisplayName('Salesforce Support');

              mail.setSubject('Your Opportunity is now Closed Lost');
              String body = '' + opp2.Owner.Name + ', <br/>';
               body+='Here is a link for you to see the Opportunity that has changed to a Closed Lost Stage:  link/' +opp2.Id +'<br/>';
               body+= 'Thank you,'+'<br/><br/>';
               mail.setHtmlBody(body);
               mails.add(mail); 
            }

        update oppListTest2;
        System.debug('Size of the list of Opportunities: '+mails.size());
        Messaging.sendEmail(mails); 

    }

}

This is my test class:

@isTest 
public class OpportunityClosedLostTest {

    public testmethod static void ClosedOpportunities(){
        Datetime oneyearago = System.today().addDays(-365);
        String value = Json.serialize(oneyearago);
        List<Opportunity> opplist1 = new List<Opportunity>();

    OpportunityClosedLost oc= new OpportunityClosedLost();
        Datetime oneweekbefore = System.today().addDays(-358);
        String value2 = Json.serialize(oneweekbefore);
        List<Opportunity> opplist2 = new List<Opportunity>();

        String OppJSON = '{"attributes":{"type":"Opportunity","url":"/services/data/v25.0/sobjects/Opportunity/500E0000002nH2fIAE"},"Id":"500E0000002nH2fIAE","LastModifiedDate":'+value +'}';
        Opportunity opp = (Opportunity) JSON.deserialize(OppJSON, Opportunity.class );
        System.debug(opp.LastModifiedDate);   
        opplist1.add(opp);    

        String OppJSON2 = '{"attributes":{"type":"Opportunity","url":"/services/data/v25.0/sobjects/Opportunity/500E0000002nH2fIAF"},"Id":"500E0000002nH2fIAF","LastModifiedDate":'+value2 +'}';
        Opportunity opp2 = (Opportunity) JSON.deserialize(OppJSON2, Opportunity.class );
        System.debug(opp2.LastModifiedDate);   
        opplist2.add(opp2);

        System.debug('Opp Id: '+ opp2.Id);

        Test.startTest();
       // OpportunityClosedLost(opplist1,opplist2);
        oc.execute();
        Test.stopTest();

        }
}

And this is the Job:

public class OppsClosedLostJob implements Schedulable{

  public void execute(SchedulableContext SC) {
     OpportunityClosedLost oc= new OpportunityClosedLost();
     oc.execute(); 
  }

}

What should I change to make it work? Thanks in advanced!

2
  • Why do you want to test it using real data ? As per best practice, we should always create data in Test class otherwise chances of failing tests are high and by the time deployment could also be very slow in case of LDV. Jan 26 '16 at 17:45
  • I want my test class to use the fake data I create during testing.
    – Leo
    Jan 26 '16 at 18:32
1

You just need two constructors - one that is as you have it, and another that looks something like this:

public OpportunityClosedLost() {
  this([SELECT Id,OwnerId,Owner.Name, Owner.Email From Opportunity WHERE IsClosed = False AND Is_in_queue__c = False AND
                                    DB_Opportunity_Age__c = 358 ],
       [SELECT Id,OwnerId,Owner.Name, Owner.Email From Opportunity WHERE IsClosed = False AND Is_in_queue__c = False AND
                                    DB_Opportunity_Age__c = 365 ]);
}

The test method should call the first. However, two things to note: First, I think you're going to get into trouble since I believe update will fail on faked data. Second, this is not dependency injection. There's no dependency being injected, just a parameter, really. A true DI setup would involve injecting classes that implement an interface. This makes the production-injected dependency testable, as well, while here you're just hoping it works.

Also, it would be even better to make the "test" constructor @TestVisible private.

But really, I'd break your execute method into pieces, and pass parameters around anyway. That would make it much easier for someone to see what's happening.

5
  • Charles, thank you for your response, I think this is more what I was looking for. Now, once I create this new constructor, how should I call execute from my test class passing the 2 lists I created in my test?
    – Leo
    Jan 27 '16 at 17:10
  • @Leo I don't understand your question. Please try it out and if you run into difficulty, ask a more specific question. Jan 27 '16 at 17:50
  • So..I added your code and ran my test and it failed, the Debug log says this: 13:18:27.0 (6148244)|FATAL_ERROR|System.NullPointerException: Attempt to de-reference a null object Class.OpportunityClosedLost.execute: line 34, column 1 Class.OpportunityClosedLostTest.ClosedOpportunities: line 28, column 1 And that is this line: for (Opportunity o:oppListTest1) in my class.
    – Leo
    Jan 28 '16 at 16:46
  • glad you wrote a test case. Sounds like your code isn't working. I assume you can debug a null pointer exception. Jan 28 '16 at 20:41
  • btw, my code had nothing to do with your test case. I think you must be missing something conceptually. Jan 28 '16 at 20:42
0

I'm not sure I understand your question - however, I think that you might be wanting to determine if you are running a test or not. The method to use is Test.isRunningTest(). Your code could look like this:

if (Test.isRunningTest()){
   //do test stuff
}
else {
   // do normal stuff
}
1
  • All I'm trying to do is, if the test is running, I would like to pass in the parameters, the 2 lists that I created in my test class and iterate over those lists, but if those lists are empty (what means, the test is not running), then do a query, get the list that I need and iterate over this new list. Does it make sense?
    – Leo
    Jan 26 '16 at 23:03

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.