I've tried to find a case that is relatable to mine with a standard controller and class extension with a test class that is seeing this same issue, but I've been unsuccessful.

I created a custom VF related list that references a standardController with a class extension. The VF related list is on the opportunity, pulling in through a query on the apex class, the synced quote's service (QService__c object) line items. If there are no line items, it displays a message. Here is the VF code to give some context.

<apex:page standardController="Opportunity" extensions="serviceViewController" lightningStyleSheets="true">
<apex:form >

    <!-- Display related list if there is a service on synced quote -->
    <apex:pageBlock id="section1" rendered="{!section1}" title="Services">
        <apex:pageBlockTable value="{!getQServices}" var="qservice">

            <!-- ID Column w/ related link -->
            <apex:column headerValue="Id">
            <apex:outputLink value="{!URLFOR($Action.QService__c.View, qservice.Id)}" title="Id">

            <!-- Name Column -->
            <apex:column value="{!qservice.Name}"/>

            <!-- Total Service Cost Column -->
            <apex:column value="{!qservice.Total_Service_Cost__c}"/>


    <!-- Display catch error on if no service records on synced quote or no synced quote. -->
    <apex:pageBlock id="section2" rendered="{!section2}" title="Services">
            You need a synced quote with service records for this list to populate. 

The class and the VF page work just fine. They function as designed. Here is the apex class code.

public class serviceViewController {

public Opportunity opp; //Create opp var
public List<QService__c> getQServices{get; set;} //List to pull in values from Qservice__c for related list.
public boolean section1{get; set;} //used for deciding what to render on VF page.
public boolean section2{get; set;} //used for deciding what to render on VF page.

//Controller Extension
public serviceViewController(ApexPages.StandardController controller) {
    this.opp = (Opportunity)controller.getRecord();

    //Pull in columns for QService__c and load into getQServices
    getQServices = [SELECT Id, Name, Total_Service_Cost__c
                    FROM QService__c
                    WHERE Opportunity__c = :opp.Id 
                    AND Synced_Service__c = TRUE

    //Set to TRUE if there IS services on the synced quote.
    boolean recordsExist = ![SELECT Id FROM QService__c WHERE Opportunity__c = :opp.Id AND Synced_Service__c = TRUE LIMIT 1].isEmpty();

    //If records do exist, set section1 to TRUE to render the related list, otherwise display catch error VF display.
    if(recordsExist == TRUE){
        section1 = TRUE;
        section2 = FALSE;
    } else if(recordsExist == FALSE){
        section1 = FALSE;
        section2 = TRUE;

My issue is with the test class. Looking through the code you can see that it's self-explanatory. An account is created, then a contact, then an opp, with a quote, and then a service record. Then the freshly quote is set as the synced quote.

The test class was able to save, but I was getting 0% code coverage in my class and I realized I should be calling an instance of my APEX class so it can initialize my VF page when the test class is run. You'll see in the syntax the last commented code and it's line. That's where I'm running into an issue. Construct not defined: [serviceViewController].()

private class serviceViewControllerTestClass {
public static Opportunity opportunityInstance {get; set;}    

@isTest static void createEverything() {

    //Create Account
    Account acc = new Account();
    acc.Name = 'Test Account';
    insert acc;

    //Create Contact
    Contact con = new Contact();
    con.FirstName = 'Kruse';
    con.LastName = 'Collins';
    con.AccountId = acc.Id;
    con.LeadSource = 'Event';
    con.Contact_Role__c = 'VP';
    insert con;

    //Create Opportunity
    Opportunity opp = new Opportunity();
    opp.Name = 'Test Opp';
    opp.CloseDate = date.today();
    opp.Accountid = acc.Id;
    opp.Contact2__c = con.Id;
    opp.Stagename = 'Discover and Assess';
    opp.Holdout_Opportunity__c = FALSE;
    opp.ForecastCategoryName = 'Commit';
    opp.Sales_Process_Stage__c = 'Discover and Assess';
    opp.Forecast_Percentage_NEW__c = 15.00;
    opp.Turn_Off_Initial_CX_EX_RC_Amounts__c = TRUE;
    Map<String,Schema.RecordTypeInfo> rtMapByName = Schema.SObjectType.Opportunity.getRecordTypeInfosByName();
  //opportunityInstance.RecordTypeId = rtMapByName.get('XM').getRecordTypeId();
    insert opp;

    //Create Quote
    Quote qt = new Quote();
    qt.Name = 'Test Sync Quote';
    qt.OpportunityId = opp.Id;
    qt.License_Term_in_months__c = 12.00;
    insert qt;

    //Create Service Record
    QService__c srvc = new QService__c();
    srvc.Name = 'Synced Service';
    srvc.Service_Type__c = 'TAM';
    srvc.Quote__c = qt.Id;
    insert srvc;

    opp.SyncedQuoteId = qt.Id;
    update opp;

    //This is where I'm getting the constructor not defined error
    serviceViewController sv = new serviceViewController();


Anything helps with figuring this out. What might be throwing this error? Is it the naming of the extension and the class? Or is it scope? As well, is this even the right direction I'm going with trying to get full coverage of my APEX text class?

  • You are not writing a controller. You are writing an extension. Naming your class serviceViewController is misleading.
    – Adrian Larson
    Commented Mar 22, 2018 at 18:03

1 Answer 1


Your controller extension has one constructor:

public serviceViewController(ApexPages.StandardController controller) 

It takes a single parameter, an ApexPages.StandardController instance. You are calling a constructor with no parameters:

serviceViewController sv = new serviceViewController();

which does not exist.

You'd need to change this line of code to

serviceViewController sv = new serviceViewController(new ApexPages.StandardController(opp));

to get it to compile.

Remember that you need to then add assertions to your test to demonstrate that your code's behavior is what is expected. It looks like this would consist of inspecting the getQServices (by the way, naming a variable getXXX which has a getter is going to cause confusion), section1, and section2 variables for appropriate values.

  • That was exactly what the issue was. I added that and it bumped me up to 85% code coverage - but I'll add the assertions to get that all set and good to go. Thank you so much for the help, David! I hope this question helps other people with the same issue. Commented Mar 22, 2018 at 19:15

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .