2

I was in the process of updating the API version of all the old classes and triggers in our org (noticed alot of them were in version 15-18 instead of 41+). Everything wen successfully, except for one class. I noticed that this class had its test class written inside it, which is a big no-no. This is the original version of the class:

public with sharing class scheduleOverride {

    private final OpportunityLineItem oli;
    public Boolean hasSchedule = false;
    public Boolean needsToEstablish = false;
    public Boolean canPushbutton = false;


    public scheduleOverride(ApexPages.StandardController stdController) {

        this.oli = (OpportunityLineItem)stdController.getRecord();
        List<OpportunityLineItemSchedule> thisScheduleList = [Select Id From OpportunityLineItemSchedule Where OpportunityLineItemId = :oli.Id];

        Opp_Sched_Update__c soeUser = Opp_Sched_Update__c.getInstance(); 

        canPushbutton = soeUser.Can_Update__c;

        if(thisScheduleList.size() > 0 && canPushbutton) {hasSchedule = true;}
        if(thisScheduleList.size() == 0) {needsToEstablish = true;}

    }
    public Boolean getneedsToEstablish() {

        return needsToEstablish;
    }   
    public Boolean getcanPushbutton() {

        return canPushbutton;
    }   

    public Boolean gethasSchedule() {

        return hasSchedule;
    }
    public PageReference editOverride() {

        String url = '/oppitm/scheduleedit.jsp?id='+oli.Id+'&sUrl=/'+oli.Id+'&retURL=/'+oli.Id;
        PageReference pageRef = new PageReference(url);
        pageRef.setRedirect(true);
        return pageRef;
    }

    public PageReference reEstablishOverride() {

        String url = '/oppitm/establishschedule.jsp?id='+oli.Id+'&retURL=/'+oli.Id;
        PageReference pageRef = new PageReference(url);
        pageRef.setRedirect(true);
        return pageRef;
    }

    public PageReference deleteOverride() {

        List<OpportunityLineItemSchedule> thisScheduleList = [Select Id From OpportunityLineItemSchedule Where OpportunityLineItemId = :oli.Id];

        delete thisScheduleList;

        PageReference pageRef = ApexPages.currentPage();
        pageRef.setRedirect(true);
        return pageRef;
    }

    static testMethod void testCloneOpptyBtn(){

    Salesperson__c sp = TestDataFactory.createTestSalesperson('Test User', true);
    Account nAccount = TestDataFactory.createTestAccount('Test Account', '123456', sp.Id, true);       

    Opportunity nOpp = new Opportunity();
    nOpp.name = 'Test';
    nOpp.StageName = 'Test';
    nOpp.closeDate = System.Today();
    insert nOpp;

    PricebookEntry pbook2 = [select id from PricebookEntry Limit 1];

    OpportunityLineItem nLi= new OpportunityLineItem();
    nLi.OpportunityId = nOpp.Id;
    nLi.Quantity = 1.0;
    nLi.TotalPrice = 2;
    nLi.PricebookEntryId = pbook2.Id;
    insert nLi;

    PageReference pageRef = Page.productViewOverride;
    Test.setCurrentPage(pageRef);
    ApexPages.StandardController sc1 = new ApexPages.StandardController(nLi);                   
    scheduleOverride controller1 = new scheduleOverride(sc1);
    controller1.deleteOverride();  
    controller1.editOverride();
    controller1.getcanPushbutton();
    controller1.gethasSchedule();
    controller1.getneedsToEstablish(); 
    controller1.reEstablishOverride();                  

  }    

}

So I decided to take the test method out and write it in its own class. This is what I have wrote:

@isTest
public class scheduleOverrideTest {
    static testMethod void testCloneOpptyBtn(){

    Salesperson__c sp = TestDataFactory.createTestSalesperson('Test User', true);
    Account nAccount = TestDataFactory.createTestAccount('Test Account', '123456', sp.Id, true);       

    Opportunity nOpp = new Opportunity();
    nOpp.name = 'Test';
    nOpp.StageName = 'Test';
    nOpp.closeDate = System.Today();
    insert nOpp;

    PricebookEntry pbook2 = [select id from PricebookEntry Limit 1];

    OpportunityLineItem nLi= new OpportunityLineItem();
    nLi.OpportunityId = nOpp.Id;
    nLi.Quantity = 1.0;
    nLi.TotalPrice = 2;
    nLi.PricebookEntryId = pbook2.Id;
    insert nLi;

    PageReference pageRef = Page.productViewOverride;
    Test.setCurrentPage(pageRef);
    ApexPages.StandardController sc1 = new ApexPages.StandardController(nLi);                   
    scheduleOverride controller1 = new scheduleOverride(sc1);
    controller1.deleteOverride();  
    controller1.editOverride();
    controller1.getcanPushbutton();
    controller1.gethasSchedule();
    controller1.getneedsToEstablish(); 
    controller1.reEstablishOverride();                  

  }    

}

However, when I am running the test code, SF is saying test method failed for the following reason:

System.QueryException:List has no rows for assignment to SObject ?Class.scheduleOverrideTest.testCloneOpptyBtn: line 14, column 1

This doesn't make sense to me because I ran a query in the Query editor and I am getting several price book entries. So that query should return something in the code. Any ideas on how to fix this issue so that I can run my test class?

3

If this code was written in API 15/18 then those tests relied in existing data to work. Now, they cannot. You have two ways to fix this problem:

  1. Do not use this method This method is only for extreme cases, and bad practice (as a rule). However, I mention it here because it is a possibility and it may come handy to you in your future endeavors

    You can make your tests see all data by changing the first line of your test to this: @isTest(SeeAllData=true)

  2. Use THIS Ideally, what you want to do is create a @TestSetup method in your class (see here). In your case, it could look like this

    @testSetup 
    static void setupData() {
    
        //Add a product to it
        Product2 prod = new Product2(Name='Test Prod', Description='Test Prod Description');
        insert prod;
    
        //Get the standard PricebookId (via a test-specific method)
        Id pbid = Test.getStandardPricebookId();
    
        //Add a pricebook entry
        PricebookEntry pbe = new PricebookEntry (Pricebook2Id=pbid, Product2Id=prod.id, IsActive=true, UnitPrice=100.0);
        insert pbe;
    
    }
    

    Then, in your code, replace this line:

    nLi.PricebookEntryId = pbook2.Id;
    

    with this one

    nLi.PricebookEntryId = pbe.Id;
    

Other things to do

There are a few more things that you should do to make your test code even better practice. They are not strictly necessary here but you should take the time (if you can) to learn these techniques and improve your test code so it fulfills the intended objective (not just cover the code, but ensure it works) (selected extracts from here)

  • Use System.assert methods to prove that code behaves properly.
  • Set up test data
  • Create all test data before calling the Test.startTest method.
  • Make calls to methods using both valid and invalid inputs.

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.