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
Dchris222Dchris222 

Test Method Help

This is my first salesforce project endeveour and I am struggling to get it done on time. I have tested my apex class and it works as expected, but now I need to create test methods so that I can deploy it into Salesforce but I am struggling to grasp what I need to do.  I have read the documentation, but not still am not sure how to best setup this up. I would really appreciate it if you could help a beginner out!

 

Thanks in advance!

 

Here is my apex class:

 

 

global class OppPoliceController {
 
  public void Opportunity1() {
 
     List<Opportunity> Opptys2 = [SELECT name, LastActivityDate, Activity_Status__c, StageName, (SELECT CreatedDate FROM Feeds ORDER BY CreatedDate DESC limit 1), (SELECT Status FROM Tasks) FROM Opportunity WHERE StageName != 'Closed Won' AND StageName != 'Closed Lost' ORDER BY LastActivityDate DESC];
 
	
        for(Opportunity Op : Opptys2){
        
        datetime LastActivityDate = Op.LastActivityDate; //Last Activity Date in datetimeformat
        datetime CreatedDate = null;
       
        datetime CreatedDate1 = Op.Feeds[0].CreatedDate;  //Created Date in datetime format 
        datetime d = Date.today();  //Current Date Formated
        
        string status1 = '';
        
        if(Op.Tasks != Null && !Op.Tasks.isEmpty())  {
        	
        	 Status1 = Op.Tasks[0].Status;
        }
        else {
        	
        	system.debug('error');
        }
        	
        System.debug('This is the created date: ' + CreatedDate1);
        System.debug('This is the status: ' + Status1);
        System.debug('This is todays date: ' + d); 
        
            if(LastActivityDate == Null) { 
            	
            	if(d < CreatedDate1.addDays(7) || Status1 == 'In Progress' || Status1 == 'Waiting on someone else' || Status1 == 'Deferred') {
            		
            		 Op.Activity_Status__c = 'Low'; //low
            		 	 
            	}
            	 else if(Status1 == 'Not Started' && d > CreatedDate1.addDays(14)) {
            	
            	 Op.Activity_Status__c = 'High'; //High
            	     	 
            	}
            	 else if(d >= CreatedDate1.addDays(7) && d < CreatedDate1.addDays(14)) {
         
                 Op.Activity_Status__c = 'Medium'; //Medium
               
                  }
                  else {
                  	
                  	 Op.Activity_Status__c = 'error';
                  }
                          	
            }
           
            else if(d > LastActivityDate.addDays(14) || d > CreatedDate1.addDays(14)) {
              
              Op.Activity_Status__c = 'High'; //High
              
            }
            
            else if((d >= CreatedDate1.addDays(7) && d < CreatedDate1.addDays(14))
            	&& (d >= LastActivityDate.addDays(7) && d < LastActivityDate.addDays(14)) ) {
         
               Op.Activity_Status__c = 'Medium'; //Medium
               
            }
              
            else if(d < LastActivityDate.addDays(7) || d < CreatedDate1.addDays(7) || Status1 == 'In Progress' || Status1 == 'Waiting on someone else' || Status1 == 'Deferred') {
            	
                Op.Activity_Status__c = 'Low'; //Low
                
            }
            	
            else {
            
                Op.Activity_Status__c = 'Error';
                   
            }
        }    
           update Opptys2;
  }     
}

 

 

This is the start of my Test Class..

 

 

@isTest
private class OppPoliceTestClass {
  static testMethod void testOpportunity1()  {
  
    

  }
}
    

 

 

MJ09MJ09

Good start to your test class, but you do need a bit more detail in there.... :)

 

From a quick scan of the method you want to test, it looks like you find a bunch of Opportunities that meet certain criteria, then update them. Your test method should:

 

1. Create a bunch of Opportunities, some of which meet the criteria, and others that don't. Insert those Opps into the database. (Because this code will be running in a test context, those Opps will be visible only to the test, and will be deleted after the test completes, so you don't have to worry about cleaning up the Opps when teh test is over.)

 

2. Instantiate the class and call the method.

 

3. Query the database to retrieve the Opportunities you just inserted. Use System.assertEquals() calls to ensure that the method correctly updated the Opps that it should have updated, and didn't update the Opps that didn't meet the criterial.

 

You said this is your first Salesforce project, so if you don't mind, here are a few other suggestions:

 

 

  • Your class name contains the word "Controller," which usually indicates that it's a controller for a Visualforce page. If it is, great, but if not, I'd suggest renaming the class to avoid future confusion.
  • Your method name, Opportunity1, isn't particularly meaningful. I usually use verbs for method names, because they tell me what the method does. 

 

You might want to review samples of Apex code written (like maybe those in the Apex manual) with regard to conventions like upper/lower case for class names and variable names. Those things aren't mandatory, but following those conventions will help make your code more readable in the long term. 

 

Have fun!

Dchris222Dchris222

Ok I have tried what you said and run into a couple questions/problems. For your second point, how do I Instantiate the class and call the method in my test class? Also for the system.asertEquals() I am running into this error message: " Save error: Comparison arguments must be compatible types: String, LIST<Opportunity>" What am I doing wrong? Thank you for your help!

 

 

@isTest
private class OppPoliceTestClass {

    static testMethod void testOpportunity1() {
    	  
      date d = Date.today();
        
      Opportunity Opp = new Opportunity();
      Opp.name = 'Op-Test8';
      Opp.StageName = 'Open';
      Opp.CloseDate = d + 7;
      
      Task t = new Task();
      t.OwnerId = '005Q0000000bRd0IAE';  //my id
      t.Subject='Send out Notice';
      t.Status = 'In Progress';
      t.Priority = 'Normal';
      
      insert Opp;
      insert t;
      
      List<Opportunity> Opptys2 = [SELECT name, LastActivityDate, Activity_Status__c, StageName, (SELECT CreatedDate FROM Feeds ORDER BY CreatedDate DESC LIMIT 1), 
                          (SELECT Status FROM Tasks) FROM Opportunity WHERE Name = 'Op-Test8' ORDER BY LastActivityDate DESC];
     
     
      for(Opportunity Op : Opptys2){
     	
   System.assertEquals('Low',[select o.Activity_Status__c from Opportunity o WHERE name= 'Op-Test8']);  	
    
     }                    			
   }
}

 

 

MJ09MJ09

First, take a look at how you're creating your test data. Is the Task associated with the Opportunity in such a way that when your method runs, the query will find the Task?  Instead of instantiating the Opp and Task and then inserting them, you should create just the Opp and insert it. When you insert the Opp, the system will automatically set its Id to the Id of the newly created record. Then create the Task, set the Task's WhatId to refer to the Opportunity's Id, and insert the Task. That will link the Task to the new Opportunity, so your class will be able to find it.

 

You asked how you instantiate the class so you can call it from your test. Inside your test, you'll need to do something like this:

 

 

OppPoliceController myClass = new OppPoliceController();
myClass.Opportunity1();

 

You said you're getting the error " Save error: Comparison arguments must be compatible types: String, LIST<Opportunity>" from this line of code:

 

 

System.assertEquals('Low',[select o.Activity_Status__c from Opportunity o WHERE name= 'Op-Test8']);  

 

 

The two arguments to assertEquals() have to be of the same (or compatible) types. Your first argument is a String. Your second argument is the list of Opportunity records returned by your query. Typically, in this kind of test, you'd have a statement before the System.assertEquals() that queries the database to retrieve the Opportunity, and then your System.assertEquals() method would refer to a property of that Opportunity. 

 

For what it's worth, the questions you're asking are pretty typical questions for people who are just getting started with Apex. They're perfectly appropriate for your experience level. However, if I were a system admin in your org, I'd be a little concerned about the notion of you deploying code into Production, given that you are so new to Apex. I know you're got an immediate problem to solve, but I suggest you consider taking some online training, or better yet, taking the Apex class from Salesforce. If you're going to be developing Production code, you really do need to have a solid grounding in a lot more areas than you do right now.

 

Best wishes--

Dchris222Dchris222

Ok I think i understood what you were saying. I first created a new Opp and then query that Opp to get it's Id. Next I created a new task and set the WhatId to the OppId (I hope correctly). I then instantiate my class so that it can be evaluated. Finaly, I querried the Opportunity Activity Status field to see if it was populated correctly. Does everything look to be correct?

 

 

@isTest
private class OppPoliceTestClass {

    static testMethod void testOpportunity1() {
    	
      //TO DO: implement unit test
   
      date d = Date.today();
        
      Opportunity Opp = new Opportunity();
      Opp.name = 'Op-Test8';
      Opp.StageName = 'Open';
      Opp.CloseDate = d + 4;
      
      insert Opp;
        
      List<Opportunity> OppId = [SELECT Id FROM Opportunity WHERE name = 'Op-Test8'];
      
      for(Opportunity Op1 : OppId){
      	
           string ID = Op1.Id;
       
           Task t = new Task();
           t.OwnerId = '005Q0000000bRd0IAE';
           t.Subject='Send out Notice';
           t.Status = 'In Progress';
           t.Priority = 'Normal';
           t.WhatId = ID;
      
           insert t;
      }
      
      OppPoliceController myClass = new OppPoliceController();
	  myClass.Opportunity1();
      
	
	  List<Opportunity> OppStatus = [select o.Activity_Status__c from Opportunity o WHERE name= 'Op-Test8'];	
     
      for(Opportunity Op2 : OppStatus){
      	
      	System.assertEquals('Low',Op2.Activity_Status__c);
      	
      }                  			
   }
}

 

 

 

 

MJ09MJ09

It'll probably work, but you're working way too hard. Right after you insert the opp, Salesforce sets its Id field to contain the newly created record's Id. You don't have to query on the Opp's name to get the Id -- it's right there in Opp.id.

 

 

...
insert Opp;

System.debug('The new Opp is is  ' + Opp.id);

 

So in both places where you're querying based on the Opp's name, I'd change that code to use Opp.id.

 

Dchris222Dchris222

Ok, it looks like I am at 64% code coverage and I think I need to create test Opportunity feed items. The problem is that none of the fields are writeable. Any ideas on why? 

 

OpportunityFeed Opf = new OpportunityFeed();
      Opf.Type = 'TextPost';
      Opf.Body = 'This is a test';
      Opf.ContentData = 'string';

      Opf.CreatedDate = Today() - 7;

      .....

 

Also it appears I am geting a "List out of bounds: 0" error when adding the CloseDate for my Opportunity.

 

 

MJ09MJ09

OpportunityFeed.Type is a picklist. The value you assign to it must be a String, so put the value in quotes.

 

CreatedDate is never writable. 

 

Beyond that, I've never created a Feed record, so I'll have to defer to someone who has.

Dchris222Dchris222

How am I supposed to test something that isn't writable to create test data? Should I query an existing record and test it that way? Also once I have a test case done and I want to add another to cover my scenarios do I need to create a separate test class or can I just add another  static test method to the page?


Btw I really appreciate you answering my barge of questions. You have been extremely helpful thus far.


Ritesh AswaneyRitesh Aswaney

The same testclass can have multiple testMethods for testing different test cases.

CreatedDate doesnt need to be set, it is auto populated as one of the audit fields by Salesforce.

MJ09MJ09

> You have been extremely helpful thus far.

 

Thus far.... :)

 

Whenever I post a question, I try to answer a question. Seems like good karma to do that. Although I kind of think I've built up a lot of good karma on this one....

 

You'll have to write your test with the knowledge that CreatedDate is always set to the current date/time. 

 

Your test class can contain several test methods. Just add another static test method to the class.

 

As long as I'm on a roll, let me reiterate my earlier suggestion that you attend training, either online or in person. While you can brute-force a solution into place, Production isn't usually the place to do that. You really should have a good solid knowlege of Apex, or work with someone who does.

 

As it happens, my company, OpFocus, is a Salesforce.com consulting partner, and many of us write Apex every day for our customers. However, I don't want you to think that I'm using this post to troll for business. Regardless of whom you go to, you really should have not just your code, but your approach and design, reviewed by someone who knows Apex well enough to understand how your solution fits into the big picture.

 

Good luck!

Dchris222Dchris222

Ok  here is a new one for you...When I try and deploy the apex class my test class meets the code% but it has a "Run Failure":

 

OppPoliceTestClass.testOpportunity1 System.DmlException: Update failed. First exception on row 855 with id 0063000000ZbLcbAAF; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, opptySwarm: execution of AfterUpdate caused by: System.LimitException: Too many future calls: 11

 

I am extremely confused as my test data and my class does not have any Future calls. Is this becuase of a Test, trigger, or class that someone else developed that is firing when I update the field?? Any ideas on ho can I fix it or a workaround?

 

Thanks for your help, I know you have gone above and beyond what you normally do.

MJ09MJ09

OppPoliceTestClass.testOpportunity1 System.DmlException: Update failed. First exception on row 855 with id 0063000000ZbLcbAAF; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, opptySwarm: execution of AfterUpdate caused by: System.LimitException: Too many future calls: 11

 

Yikes! Looks like you've got a lot more happening in your org than this simple class and unit test! When your test runs, something (probably a trigger named opptySwarm) is trying to insert at least 855 rows. What could be doing that, and why? 

 

Second, something (probably the same trigger) is issuing an @future call, trying to get some processing to happen asynchronously. You can only do that 10 times per transaction, and it's failing on the 11th attempt.

 

The issue doesn't appear to be your code or your test, but rather something that happens when your code runs. Without taking a look at all other possibly-related code in your org (including any Opportunity triggers, and anything those triggers call), it's impossible to tell what's going on. 

 

Remember what I said about having your code looked at by someone who knows Apex well enough to understand how your solution fits into the big picture? Now would be a good time for that.

 

Best wishes--