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
Dea73Dea73 

Unit test for a class

Hi all,

 

I'm getting the hang of writting a unit test for triggers. But now i'm wondering how to do it for a class.

 

I have the class below, which is a wrapper class. How on earth do i write a unit test for it?

Any help would be greatly appreciated!!!!

 

public class newWorkOrderWizardController {


private final Work_Order__c workOrderObj;

public newWorkOrderWizardController(ApexPages.StandardController controller) {
  this.workOrderObj = (Work_Order__c)controller.getRecord();
 

}
   
Work_Order__c workorder;
Work_on_Circuit__c woc;

public Work_Order__c getWorkOrder(){
if(workorder == null) workorder = new Work_Order__c();
return workorder;
}

public Work_on_Circuit__c getWorkonCircuit(){
if(woc == null) woc = new Work_on_Circuit__c();
return woc;
}


public PageReference step2(){

return Page.displaycircuits;

}


public PageReference stepBack(){

return Page.createWorkOrder;

}

public PageReference cancel() {
    PageReference workorderPage = new PageReference('/a05/o');
    workorderPage.setRedirect(true);
    return workorderPage;
    }

 

public List<circuitWrapper> circuitList{get;set;}
public List<offCircuitWrapper> offCircuitList{get;set;}

public List<circuitWrapper> getCircuits(){
   ID idcpe = workorder.CPE_Location__c;
   
   if(circuitList == null){
   circuitList = new List<circuitWrapper>();
  
   for(Circuits__c ckt : [select Id,Name, Circuit_ID__c,Service_Level__c,Circuit_Status__c from Circuits__c where Circuits__c.A_CPE_Location_LU__c =: idcpe]){
  
      circuitList.add(new circuitWrapper(ckt));
   }
  }   return circuitList;
   
}

 

public List<offCircuitWrapper> getOffCircuits(){
   ID idlocation = workorder.Location__c;
  
   if(offCircuitList == null){
   offCircuitList = new List<offCircuitWrapper>();
  
   for(Circuits__c ockt : [Select c.Service_Level__c, c.Name, c.Id, c.Circuit_Status__c, c.Circuit_ID__c From Circuits__c c where RecordTypeId = '01230000000LSRd' and Circuit_Status__c = 'Active' and Z_Location_LU__c =: idlocation]){
  
      offCircuitList.add(new offCircuitWrapper(ockt));
   }
  }   return offCircuitList;
   
}


public class circuitWrapper{

public Circuits__c ckt{get;set;}
public Boolean selected{get;set;}

public circuitWrapper(Circuits__c c){

 ckt = c;
 selected = false;

}
}

public class offCircuitWrapper{

public Circuits__c ockt{get;set;}
public Boolean oselected{get;set;}

public offCircuitWrapper(Circuits__c offc){

 ockt = offc;
 oselected = false;

}
}

 


public PageReference save(){

// create work order
insert workorder;


  
List<Circuits__c> selectedCircuits = new List<Circuits__c>();
  
     for(circuitWrapper cktwrapper : getCircuits()){
      if(cktwrapper.selected == true){
          selectedCircuits.add(cktwrapper.ckt);
      }
  }
 
  for(Circuits__c ckt : selectedCircuits){
   Work_on_Circuit__c ckts = New Work_on_Circuit__c(Circuit__c = ckt.id, Work_Order__c = workorder.id);
   insert ckts;
     
  }


List<Circuits__c> selectedOffCircuits = new List<Circuits__c>();
  
     for(offCircuitWrapper ocktwrapper : getOffCircuits()){
      if(ocktwrapper.oselected == true){
          selectedOffCircuits.add(ocktwrapper.ockt);
      }
  }
   
for(Circuits__c ockt : selectedOffCircuits){
   Work_on_Circuit__c ockts = New Work_on_Circuit__c(Circuit__c = ockt.id, Work_Order__c = workorder.id);
   insert ockts;
     
  }
 
 PageReference woPage = new ApexPages.StandardController(workorder).view();
      woPage.setRedirect(true);

      return woPage;
 
  
  
  
}  

 

sfdcfoxsfdcfox

Technically, if your unit test is already testing everything it should, your wrapper classes should already be fully tested. This means that you should be simulating a user moving through your page, such as:

 

 

public static void testMethod test() {
  Test.setCurrentPage(Page.myPage);
  ApexPages.StandardController sc = new ApexPages.StandardController(new Work_Order__c());
  newWorkOrderWizardController wowcon = new newWorkOrderWizardController(sc);
  // Test your various lists to make sure they're populating correctly
  // System.assert and System.assertEquals are useful here
  
}

Couple of side notes worth mentioning here:

 

 

1) The cancel() function isn't necessary, as the controller provides its own method. In any event, "/a05/o" will (likely) break when deploying between developer edition and production and/or sandbox. Use StandardController.cancel() or a specific Action so you can redirect them in an instance-independent manner (see the documentation for details). I'd recommend saving the StandardController in a private variable for this purpose if you need it.

2) Initializations are best done in the Constructor. For example, move getWorkOnCircuit() logic to constructor, and use the default getter (i.e. public Work_On_Circuit__c woc { get; private set; } ). For those types of lists that can be reloaded from the database at various points (perhaps such as a reset button), make a public function that refreshes the list, and call that function. Use custom getters only as necessary.

3) Bulkify your code. Your save() function iterates through a list and then saves each record one at a time. This won't work for very large lists, your page's performance will be a magnitude slower even if you're under the limits, and triggers and workflows will be far more efficient with fewer DML operations. Consider doing something like this:

 

 

    List<Work_on_Circuit__c> ockts = new List<Work_on_Circuit__c>();
    for(Circuits__c ockt : selectedOffCircuits)
        ockts.add(new Work_on_Circuit__c(Circuit__c = ockt.id, Work_Order__c = workorder.id));
    insert ockts;

 

 

Dea73Dea73

Hi sfdcfox,

 

Thanks for your help and tips.

The sentence: Test.setCurrentPage(Page.myPage);
gets me an error message when i try to save my eclipse document.

 

I still can't wrap my mind around certain things. (i'm relative new to apex)

 

The class is for a wizard that i have created, for the custom work order object.

the user will have to select 2 locations, when they click on the next button circuits that are located at these 2 locations will be displayed and the user have to select the circuits that will pertain to the workorder. (using checkboxes).

 

How do i use system.assert and system.assertequals?

sfdcfoxsfdcfox

Page.myPage should be updated to whatever you named your page (i.e. Page.SomeFancyPage or Page.CustomCalendarViewer).

 

System.Assert accepts one or two parameters, such as:

 

 

System.assert(controller.Locations.size()==5,'Expected five (5) locations');

In this hypothetical example, we have the page's controller, which has an array called Locations, and we expect there to be 5 entries in the list. In this case, if there are five entries, the line is okay and testing continues. If there are not five entries, then the code stops executing and returns the custom error message that you would see in your debug logs. You can use this with other comparisons such as "<", ">" or "!=". If the result is a true boolean, the code continues, and if it returns a false boolean, then the code stops and displays an error message in the debug logs.

 

 

Since the most common type of checking is an equality (two items being equal), there is a "shortcut" method that provides a slightly better error message, and that is done with System.AssertEquals. The same example above might be written as:

 

 

System.AssertEquals(controller.locations.size(),5,'Expected five (5) locations');

In this case, the custom error message is largely unnecessary, because the system will actuall output a message similar to the following:

 

 

System.AssertException: Actual: 3, Expected 5: 'Expected five (5) locations.'

This makes it a bit easier to quickly identify what the incorrect value was, instead of having to add some sort of translation in your custom error message (such as 'Expected five (5) locations, received ' + String.valueOf(controller.locations.size()) ).

 

 

Use System.AssertEquals whenever possible to reduce your total code size and increase the debug log's legibility.

 

 

If you'd like to post your test method that you have so far, and any related code, maybe we could help you resolve your issue.

Dea73Dea73

Hi sfdc,

Sorry for the delay in response, was busy with a different project.

I made a few changes. I changed the controller from an extension to a custom controller.

So below is the new controller and the unit test.

Thanks in advance for all your help.

Controller

public class newWorkOrderWizardController {

  
Work_Order__c workorder;
Work_on_Circuit__c woc;

public Work_Order__c getWorkOrder(){
if(workorder == null) workorder = new Work_Order__c();
return workorder;
}

public Work_on_Circuit__c getWorkonCircuit(){
if(woc == null) woc = new Work_on_Circuit__c();
return woc;
}


public PageReference step2(){

return Page.displaycircuits;

}


public PageReference stepBack(){

return Page.createWorkOrder;

}

public PageReference cancel() {
    PageReference workorderPage = new ApexPages.StandardController(workorder).view();
    workorderPage.setRedirect(true);
    return workorderPage;
    }

 

public List<circuitWrapper> circuitList{get;set;}
public List<offCircuitWrapper> offCircuitList{get;set;}

public List<circuitWrapper> getCircuits(){
   ID idcpe = workorder.CPE_Location__c;
   
   if(circuitList == null){
   circuitList = new List<circuitWrapper>();
  
   for(Circuits__c ckt : [select Id,Name, Circuit_ID__c,Service_Level__c,Circuit_Status__c from Circuits__c where

Circuits__c.A_CPE_Location_LU__c =: idcpe]){
  
      circuitList.add(new circuitWrapper(ckt));
   }
  }   return circuitList;
   
}

 

public List<offCircuitWrapper> getOffCircuits(){
   ID idlocation = workorder.Location__c;
  
   if(offCircuitList == null){
   offCircuitList = new List<offCircuitWrapper>();
  
   for(Circuits__c ockt : [Select c.Service_Level__c, c.Name, c.Id, c.Circuit_Status__c, c.Circuit_ID__c From

Circuits__c c where RecordTypeId = '01230000000LSRd' and Circuit_Status__c = 'Active' and Z_Location_LU__c =:

idlocation]){
  
      offCircuitList.add(new offCircuitWrapper(ockt));
   }
  }   return offCircuitList;
   
}


public class circuitWrapper{

public Circuits__c ckt{get;set;}
public Boolean selected{get;set;}

public circuitWrapper(Circuits__c c){

 ckt = c;
 selected = false;

}
}

public class offCircuitWrapper{

public Circuits__c ockt{get;set;}
public Boolean oselected{get;set;}

public offCircuitWrapper(Circuits__c offc){

 ockt = offc;
 oselected = false;

}
}

 


public PageReference save(){

// create work order
insert workorder;


  
List<Circuits__c> selectedCircuits = new List<Circuits__c>();
  
     for(circuitWrapper cktwrapper : getCircuits()){
      if(cktwrapper.selected == true){
          selectedCircuits.add(cktwrapper.ckt);
      }
  }
 
  for(Circuits__c ckt : selectedCircuits){
   Work_on_Circuit__c ckts = New Work_on_Circuit__c(Circuit__c = ckt.id, Work_Order__c = workorder.id);
   insert ckts;
     
  }


List<Circuits__c> selectedOffCircuits = new List<Circuits__c>();
  
     for(offCircuitWrapper ocktwrapper : getOffCircuits()){
      if(ocktwrapper.oselected == true){
          selectedOffCircuits.add(ocktwrapper.ockt);
      }
  }
List<Work_on_Circuit__c> ockts = new List<Work_on_Circuit__c>();   
for(Circuits__c ockt : selectedOffCircuits){
   ockts.add(new Work_on_Circuit__c(Circuit__c = ockt.id, Work_Order__c = workorder.id));
  
     
  }
  insert ockts;
 PageReference woPage = new ApexPages.StandardController(workorder).view();
      woPage.setRedirect(true);

      return woPage;
 
}  

 


  
}

 

 

Test Unit

 

@isTest
private class WorkOrderTest {

  static testmethod void WorkOrdertest(){
newWorkOrderWizardController controller = new newWorkOrderWizardController();         

Work_Order__c wrkorder = controller.getWorkOrder();
wrkorder.Work_Order_Type__c ='Copper to Off-Net Wavelength';
wrkorder.Work_Order_Type__c = 'Roll';
wrkorder.CPE_Location__c = 'a08Q0000003xSVo';
wrkorder.Location__c = 'a00Q0000005LiF4';

 

controller.cancel();
controller.stepBack();
controller.step2();
controller.save();
  }
}

 

sfdcfoxsfdcfox

Your class needs some help before you worry about the test methods. Here's just a few things I noticed:

 

1) You have a DML statement inside a for loop (the insert ckcs line). This is a bad practice, as it incurs a lot of overhead. Instead, create a list of Work_On_Circuit__c records and insert them all in one fell swoop. This will make your page run faster, and avoid governor limits.

 

2) I assume that workorder.location__c and workorder.cpe_location__c are selectable values, and that selecting a value should update the list of circuits. Your getter methods won't do this as it stands currently. You need to consolidate your queries into a single function, and call that function whenever you need to load or reload the list of circuits.

 

3) Your two circuit wrapper classes are redundant, and should be collapsed into a single class. If you need to distinguish between them, add a member variable that tracks the type of circuit that it is. It will make your test code easier.

 

4) Never hardcode values (i.e. a RecordTypeId) into your code. It's not dynamic, and you'll find your code won't migrate easily between organizations, if this ever becomes a concern (better safe than sorry!). Instead, use a much more portable version, such as "RecordType.Name = 'Some Record Type'" in your query, so that even if your migrate organizations, your tests won't fail.

 

5) In your test class, don't use existing records, but instead create dummy records as part of the test. This is so that some administrator somewhere down the road won't accidentally delete these records, and cause future tests to fail. Don't worry about cluttering up your database with test records, as they are only simulated data inserts, and will be rolled back when the test completes.

 

6) With just a few optimizations, I was able to consolidate your code from about 90 lines (about 3,100 characters) of non-blank, non-comment code to about 60 lines (about 2,100 characters) of code. This was done by consolidating loops, variables, and classes, combining like queries (with an if statement for loading the records into their respective variables), and a few other minor changes. No actual "functionality" was changed, though, so I expect you'd need a few more lines of code to handle some of the logic errors I saw.

 

Finally, getting to the test method, your code doesn't the wrapper class. Your test code should follow the general pseudo-code:

 

1) Insert some test locations

2) Insert some test circuits that use those locations

3) Create a new controller instance

4) Check circuits and offCircuits to verify that the list sizes match and that the individual entries match their respective test records. This is how your wrapper class will achieve 100% coverage

5) Test each page action to make sure the results are what you expect. Keep the save() function for last, and make sure that the records are inserted correctly. You'll need to do a query or two in your test method to verify that they were created correctly

 

Overall, your code is "almost, but not quite" there. 

 

Here's a modified version of your controller:

 

 

public class newWorkOrderWizardController {
	public Work_Order__c workorder { get; private set; }
	public Work_on_Circuit__c woc { get; private set; }
	public List<circuitWrapper> circuits { get; set; }
	public List<circuitWrapper> offCircuits { get; set; }
	public PageReference step2(){
		return Page.displaycircuits;
	}
	public PageReference stepBack(){
		return Page.createWorkOrder;
	}
	private loadCircuits() {
		circuits = new List<circuitWrapper>();
		for(Circuits__c ckt:
			[SELECT Id,Name, Circuit_ID__c,Service_Level__c,Circuit_Status__c,A_CPE_Location_LU__c,Z_Location_LU__c
			FROM Circuits__c 
			WHERE (A_CPE_Location_LU__c = :workorder.CPE_Location__c) OR
			(RecordTypeId = '01230000000LSRd' AND Circuit_Status__c = 'Active' AND Z_Location_LU__c = :workorder.Location__c)]) {
			if(workorder.CPE_Location__c = ckt.A_CPE_LOcation_LU__c) {
				circuits.add(new circuitWrapper(ckt,CircuitType.ONCIRCUIT,false));
			}
			else {
				offCircuitList.add(new circuitWrapper(ckt,CircuitType.OFFCIRCUIT,false));
			}
		}
	}
	public enum CircuitType { ONCIRCUIT, OFFCIRCUIT }
	public class circuitWrapper{
		public CircuitType cType { get; set; }
		public Circuits__c ckt { get; set; }
		public Boolean selected { get; set; }
		public circuitWrapper(Circuits__c c,CircuitType cirType, Boolean isSelected) {
			cType = cirType;
			ckt = c;
			selected = isSelected;
		}
	}
	public newWorkOrderWizardController() {
		loadCircuits();
	}
	public PageReference save(){
		insert workorder;
		List<circuitWrapper> allCircuits = new List<circuitWrapper>();
		allCircuits.addAll(circuits);
		allCircuits.addAll(offCircuits);
		List<Work_On_Circuit__c> newWorkOnCircuits = new List<Work_On_Circuit__c>();
		for(Circuits__c ckt:allCircuits){
			if(ckt.selected) {
				newWorkOnCircuits.add(new Work_on_Circuit__c(Circuit__c = ckt.id, Work_Order__c = workorder.id));
			}
		}
		insert newWorkOnCircuits;
		PageReference woPage = new ApexPages.StandardController(workorder).view();
		woPage.setRedirect(true);
		return woPage;
	}  
}

 Let me know what you think, and once your class is working, we can work on the test method.

 

Dea73Dea73

hi sfdcfox,

 

Once again tahnk you for all your help.

I tried to make the changes you pointed out,before i looked at the revised controller you did.

I managed to create one single query to retrieve th on and off-net circuits.

The query you wrote is a tad bit different, than what it should be :)

 

i didn't come up with the enumation part..so thank you for that.

 

But i have a tiny problem with the part to split the on and off-net circuits

 

private loadCircuits()
{
 
 circuits = new List<circuitWrapper>();
 for(Circuits__c ckt: [select Id,Name, Circuit_ID__c,Service_Level__c,Circuit_Status__c,

Circuits__c.RecordType.Name from Circuits__c where
(Circuits__c.A_CPE_Location_LU__c =: workorder.CPE_Location__c and
Circuits__c.Circuit_Status__c IN ('Active') and
Circuits__c.RecordType.Name  IN ('Customer Circuit') ) or
(Circuits__c.Z_Location_LU__c =: workorder.Location__c  and
Circuits__c.RecordType.Name  IN ('Off-Net Circuit') and
Circuits__c.Circuit_Status__c IN ('Active'))])
{
how do i split the on and off-net circuits at this point? 
if  == 'Customer Circuit'{
 
 circuits.add(new circuitWrapper(ckt,CircuitType.ONCIRCUIT,false));
}
else
{
 
 offCircuitList.add(new circuitWrapper(ckt,CircuitType.OFFCIRCUIT,false));

 

Thanks again!!!!

 

sfdcfoxsfdcfox
if(ckt.RecordType.Name=='Customer Circuit') {

 That should just about do it. Your code is looking good.

Dea73Dea73

Hi sfdcfox

 

I'm back. The final controller is below:

Could you address where i wrote with red, thaks.

 

public class newWorkOrderWizardController {
 public Work_Order__c workorder { get; private set; }
 public Work_on_Circuit__c woc { get; private set; }
 public List<circuitWrapper> circuits { get; set; }
 public List<circuitWrapper> offCircuits { get; set; }
 public PageReference step2(){
  return Page.displaycircuits;
 }
 public PageReference stepBack(){
  return Page.createWorkOrder;
 }
 private loadCircuits() { i get an error invalid constructor name
  circuits = new List<circuitWrapper>();
  for(Circuits__c ckt:
   [SELECT Id,Name, Circuit_ID__c,Service_Level__c,Circuit_Status__c,A?_CPE_Location_LU__c,Z_Location_LU__c
   FROM Circuits__c
   WHERE (A_CPE_Location_LU__c = :workorder.CPE_Location__c) OR
   (RecordTypeId = '01230000000LSRd' AND Circuit_Status__c = 'Active' AND Z_Location_LU__c = :workorder.Location__c)]) {
   if(workorder.CPE_Location__c = ckt.A_CPE_LOcation_LU__c) {
    circuits.add(new circuitWrapper(ckt,CircuitType.ONCIRCUIT,false));
   }
   else {
    offCircuitList.add(new circuitWrapper(ckt,CircuitType.OFFCIRCUIT,false));
   }
  }
 }
 public enum CircuitType { ONCIRCUIT, OFFCIRCUIT }
 public class circuitWrapper{
  public CircuitType cType { get; set; }
  public Circuits__c ckt { get; set; }
  public Boolean selected { get; set; }
  public circuitWrapper(Circuits__c c,CircuitType cirType, Boolean isSelected) {
   cType = cirType;
   ckt = c;
   selected = isSelected;
  }
 }
 public newWorkOrderWizardController() {
  loadCircuits();
 }
 public PageReference save(){
  insert workorder;
  List<circuitWrapper> allCircuits = new List<circuitWrapper>();
  allCircuits.addAll(circuits);
  allCircuits.addAll(offCircuits);
  List<Work_On_Circuit__c> newWorkOnCircuits = new List<Work_On_Circuit__c>();
  for(Circuits__c should it say circuitWrapper instead of Circuits__c  ckt:allCircuits){
   if(ckt.selected) {selected is not a field in the circuits object, it's part of the circuitwrapper class
    newWorkOnCircuits.add(new Work_on_Circuit__c(Circuit__c = ckt.id, Work_Order__c = workorder.id));
   }
  }
  insert newWorkOnCircuits;
  PageReference woPage = new ApexPages.StandardController(workorder).view();
  woPage.setRedirect(true);
  return woPage;
 } 
}

 

Working on my test class in the meantime

Thanks!!