0

I created a VisualForce page to process CSV files for people to create leads. For some reason when I go to call the method for my test class to read the CSV file I am getting the error Non static method cannot be referenced from a static context: void UploadCSVController.ReadFromFile(). Is there certain ways you need to do this for a test class?

VP Page:

<apex:page lightningStylesheets="true" controller="UploadCSVController">
<h1 style="font-size:30px"><center>Automation Upload</center></h1><br/><br/>

<apex:form id="idForm">
    <apex:pageMessages /><br/><br/>

    <apex:pageBlock tabStyle="Lead" id="idInputBlock">
        <p style="height:13px; font-size:13px"><b>Set the first column of the CSV file as LastName Field:</b></p><br/>
        <apex:inputFile value="{!fileBody}" fileSize="{!fileSize}" fileName="{!fileName}" accept=".csv" contentType="text/csv" id="idInputFile"></apex:inputFile>                 
        <!-- Input File -->
        <apex:commandButton value="Upload File" action="{!ReadFromFile}" onclick="document.getElementById('actionStatusUP').style.display = 'inline';" />  
        <!-- Upload Button to upload file -->
        <img src="/img/loading.gif" style="display:none" id="actionStatusUP" />                    
        <apex:pageBlockButtons location="bottom" >                                                                                                          
        <!-- Save Button to insert the records -->
            <apex:commandButton value="Save" action="{!save}" rendered="{! reVariableSave}" onclick="document.getElementById('imageSV').style.display = 'inline';" />
            <img src="/img/loading.gif" style="display:none" id="imageSV" />
        </apex:pageBlockButtons>
        <p style="height:13px; font-size:13px"><b><br/> 
            Please be sure to upload a .csv file. You can find an example for the file type 
            <apex:commandLink action="https://storecapital--sandboxa--c.sandbox.vf.force.com/resource/1669504995000/PitchbookTestFile?" value="here"/></b>
        </p>
        <br/>
    </apex:pageBlock>

    <apex:pageBlock rendered="{! reVariableBlock}" id="idTable">
        <apex:pageBlockSection collapsible="false" columns="2" >
            <p><b>Total Records in CSV File:&nbsp;</b></p>
            <apex:outputText value="{! totalRecords}" style="color:black" />
            <p><b>Number of Records Successfully inserted:&nbsp;</b></p>
            <apex:outputText value="{! insertedRecords}" style="color:green" />
            <p><b>Number of Failed Records:&nbsp;</b></p>
            <apex:outputText value="{! failedRecords}" style="color:red" />
        </apex:pageBlockSection><br/>
        <center><p style="color:dodgerblue;font-size:25px"><b>Details of the inserted records</b></p></center><br/><br/>
        <apex:pageBlockTable value="{! leadsList}" rendered="{! reVariable}" var="lds" >                                                           
        <!-- Table to display details of inserted records -->
            <apex:repeat value="{! fieldNamesList}" var="fld" >
                <apex:column value="{! lds[fld]}" />
            </apex:repeat>
        </apex:pageBlockTable>
    </apex:pageBlock>
    
</apex:form>
</apex:page>

Controller:

public with sharing class UploadCSVController {

//Public Variables----------------------------------------------------------------------------------------------------------------------------------------------
public transient Blob    fileBody{ get; set; }                              //fileBody
public transient Integer fileSize{ get; set; }                              //fileSize
public transient String  fileName{ get; set; }                              //fileName
public List<Lead>        leadsList{ get; set; }                             //List of inserted Leads
public List<String>      fieldNamesList{ get; set; }                        //List of fields in Lead Object's fields which are avaiable in CSV
public Boolean           reVariableSave{ get; set; }                        //Variable to render Save Button
public Boolean           reVariableBlock{ get; set; }                       //Variable to render PageBlock with inserted record details
public Boolean           reVariable{ get; set; }                            //Variable to render Record Details Table    
public Integer           totalRecords{ get; set; }                          //Total number of records in CSV File
public Integer           insertedRecords{ get; set; }                       //Number of records successfully inserted
public Integer           failedRecords{ get; set; }                         //Number of failed records

//Private Variables----------------------------------------------------------------------------------------------------------------------------------------------
String fileBodyAsString = '';                                               
//String value of file Body
String header           = '';

//Constructor----------------------------------------------------------------------------------------------------------------------------------------------------
public UploadCSVController(){
    leadsList           = new List<SObject>();
    fieldNamesList      = new List<String>();
    reVariableSave      = false;
    reVariableBlock     = false;
    reVariable          = false;
    totalRecords        = 0;
    insertedRecords     = 0;
    failedRecords       = 0;    
}

//Method to check file size and whether the file body is readable------------------------------------------------------------------------------------------------
public void ReadFromFile(){
    reVariableBlock = false;
    if(fileSize < 3280760 && fileName.substringAfterLast('.').equalsIgnoreCase('csv')){
        system.debug('file size' + filesize);
        system.debug('file name after' + fileName.substringAfterLast('.'));
        system.debug('fileBodyAsString ' + fileBodyAsString);
        system.debug('fileBody.toString() ' + fileBody.toString());
        try{
            fileBodyAsString = fileBody.toString();
            ReadCSVFile();
        }
        catch(exception e){
            ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,'Error reading CSV file'));
        }
    }
    else{
        ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,'No File Chosen or,'));
        ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,'File Size greater than 50 KB or,'));
        ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,'File is not of CSV type'));
    }
}

//Method to read the file and create a Lead list which will be inserted and check exceptions in CSV file------------------------------------------------------
private void ReadCSVFile(){
    if(fileBodyAsString.length() > 100000){
        header = fileBodyAsString.substring(0, 2000).split('\n')[0];
        system.debug('line 67 passed');
    }
    else{
        header = fileBodyAsString.split('\n')[0];
        system.debug('line 71 passed');
    }
    fileBodyAsString = fileBodyAsString.substringAfter('\n');
    system.debug('field Name List before clear ' + fieldNamesList);
    leadsList.clear();
    fieldNamesList.clear();
    system.debug('line 78 passed');
    for(String str : header.split('\n')[0].split(',')){
        fieldNamesList.add(str.trim());
    }
    system.debug('line 81 passed');
    system.debug('fieldNamesList line 81 ' + fieldNamesList);
    String                      LeadDetails         = '';
    Map<string, SObjectField>   fieldNamesMap       = Schema.getGlobalDescribe().get('Lead').getDescribe().fields.getMap();
    System.debug('Field Name List After Clear before if check ' + fieldNamesList);
    System.debug('Field Name List After Clear before if check ' + fieldNamesList[0]);
    system.debug('line 84 passed');
    System.debug('fieldNamesMap ' + fieldNamesMap);
    System.debug('LeadDetails ' + LeadDetails);
    if(fieldNamesList[0].equalsIgnoreCase('LastName')){
        System.debug('Line 91 passed');
        Lead lds                = new Lead();
        Integer flag            = 0; 
        while( !String.isEmpty(fileBodyAsString)){                                                                 
            
            //Itereation over each Lead
            if(fileBodyAsString.length() > 100000){
                leadDetails = fileBodyAsString.substring(0, 100000).split('\n')[0];
            }
            else{
                leadDetails = fileBodyAsString.split('\n')[0];
            }
            fileBodyAsString = fileBodyAsString.substringAfter('\n');
            String lastnameValue = leadDetails.substringBefore(',').trim();
            for(Integer j=0; j<fieldNamesList.size(); j++){                                                                 
                //Iterating over the fields & assigning value to them for each Lead 
                Schema.DisplayType fieldType = fieldNamesMap.get(fieldNamesList[j]).getDescribe().getType();
                if( fieldType == Schema.DisplayType.DATE ){              
                    //Setting value of fields which are of Date Type
                    try{
                        lds.put(fieldNamesList[j].trim(), Date.valueOf(leadDetails.substringBefore(',').trim()));
                    }
                    catch(Exception e){
                        flag = 1;
                        ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, 'Empty ' 
                                                                   + fieldNamesList[j].trim() 
                                                                   + ' field or Date is not in format \"YYYY-MM-DD\" for record with LastName = ' 
                                                                   + lastnameValue));
                    }
                }
                else if( fieldType == Schema.DisplayType.DATETIME ){ //Setting value of fields which are of DateTime Type
                    try{
                        lds.put(fieldNamesList[j].trim(), Datetime.valueOf(leadDetails.substringBefore(',').trim()));
                    }
                    catch(Exception e){
                        flag = 1;
                        ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, 'Empty ' + fieldNamesList[j].trim() 
                                                                   + ' field or DateTime is not in format \"YYYY-MM-DD HH:MM:SS\" for record with LastName = ' 
                                                                   + lastnameValue));
                    }
                }
                else if( fieldType == Schema.DisplayType.BOOLEAN ){  //Setting value of fields which are of Boolean Type
                    if(leadDetails.substringBefore(',').trim().equalsIgnoreCase('true') 
                       || leadDetails.substringBefore(',').trim().equalsIgnoreCase('false') 
                       || leadDetails.substringBefore(',').trim() == ''){
                        lds.put(fieldNamesList[j].trim(), Boolean.valueOf(leadDetails.substringBefore(',').trim()));
                    }
                    else{
                        flag = 1;
                        ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,  'Acceptable value for ' 
                                                                   + fieldNamesList[j].trim() 
                                                                   + ' field is \"TRUE/FALSE\" for record with LastName = ' 
                                                                   + lastnameValue));
                    }
                }
                else if( fieldType == Schema.DisplayType.TEXTAREA ){ //Setting value of fields which are of TextArea Type
                    if(leadDetails.left(1) != '\"'){                                                                 
                        //Setting value of fields which are of TextArea Type with comma
                        lds.put(fieldNamesList[j].trim(), leadDetails.substringBefore(',').trim());
                    }
                    else{                                                                                               
                        //Setting value of fields which are of TextArea Type without comma
                        lds.put(fieldNamesList[j].trim(), leadDetails.substringBetween('\"', '\"') .trim());
                        leadDetails = leadDetails.substringAfter('\"').substringAfter('\"');
                    }
                }
                else{                                                                                                   
                    //Setting value of all other type of fields
                    try{
                        lds.put(fieldNamesList[j].trim(), leadDetails.substringBefore(',').trim());
                    }
                    catch(Exception e){
                        flag = 1;
                    }
                }
                leadDetails = leadDetails.substringAfter(',');
            }
            leadsList.add(lds);
            lds = new Lead();
        }                  
        if(flag != 1){                                                                                                  
            //If there is no exception, show Save button
            reVariableSave = true;
            ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.INFO,  'Click Save Button to insert the Records '));
        }
    }
    else{
        ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,  'This has failed to work .... shit'));
    }
}

//Save method to insert the Lead Recods and counting inserted records and failed records----------------------------------------------------------------------
public Pagereference save(){
    reVariableBlock = true;
    Database.SaveResult[] srList = Database.insert(leadsList, false);
    leadsList.clear();
    Set<Id> savedLeadIdSet = new Set<Id>();
    totalRecords    = 0;
    insertedRecords = 0;
    failedRecords   = 0;
    for (Database.SaveResult sr : srList) {
        ++totalRecords;
        if (!sr.isSuccess()) {
            ++failedRecords;               
            for(Database.Error err : sr.getErrors()) {
                ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,  err.getStatusCode() 
                                                           + ': ' + err.getMessage() 
                                                           + ' for Record at Line Number: ' 
                                                           + (totalRecords + 1)));
            }
        }
        else{
            ++insertedRecords;
            savedLeadIdSet.add(sr.getId());
        }
    }
    leadsList = Database.query('SELECT ' + header + ' FROM Lead WHERE Id in :savedLeadIdSet');
    if(leadsList.size() > 0 && leadsList.size()<400){
        reVariable = true;
    }
    return null;
}
}

Test Class:

@isTest 
public class TestUploadCSVController {      

static testmethod void testfileupload(){
    String body = 'LastName,firstName,Title,Company\n Testerson, Test, CEO, Rule27\n Testing, Tester, CIO, Rule27';
    String OUTPUT_DOCUMENT_NAME = 'Test File';
    insert new ContentVersion(
        Title = OUTPUT_DOCUMENT_NAME, 
        PathOnClient = OUTPUT_DOCUMENT_NAME + '.csv', 
        VersionData = Blob.valueOf(body), 
        ContentLocation = 'S'
    );
    UploadCSVController.ReadFromFile();
} 

static testmethod void testfileuploadNegative(){
    
}
}

====================================================== After help I was able to get this solved:

Test Class:

@isTest 
public class TestUploadCSVController {      

static testmethod void testfileupload1(){
    
    String OUTPUT_DOCUMENT_NAME = 'Test File.csv';
    String body = 'LastName,FirstName,Company,Title,LeadSource,Email, STORE_Verified__c, Targeted__c, Description\n '+
        'me,Test,Test Company ,CEO,Other,[email protected],TRUE, 12/01/2022, This is a long text description. Please take a look and then tell us if this has passed.\n' +
        'you,Test,Test Company ,CIO,Other,[email protected],TRUE, 12/01/2022, This is a long text description. Please take a look and then tell us if this has passed.\n' +
        'Us,Test,Test Company ,CTO,Other,[email protected],TRUE, 12/01/2022, This is a long text description. Please take a look and then tell us if this has passed.\n' +
        'tester5,Test,Test Company ,CXO,Other,[email protected],TRUE, 12/01/2022, This is a long text description. Please take a look and then tell us if this has passed.\n' +
        'tester1,Test,Test Company ,COO,Other,[email protected],TRUE, 12/01/2022, This is a long text description. Please take a look and then tell us if this has passed.\n' +
        'tester2,Test,Test Company ,CSO,Other,[email protected],TRUE, 12/01/2022, This is a long text description. Please take a look and then tell us if this has passed.\n' +
        'tester3,Test,Test Company ,"Vp, Technology",Other,[email protected],TRUE, 12/01/2022, This is a long text description. Please take a look and then tell us if this has passed.\n' +
        'tester4,Test,Test Company ,"VP, Clicent Success",Other,[email protected],TRUE, 12/01/2022, This is a long text description. Please take a look and then tell us if this has passed.';
    Blob fileBody = Blob.valueOf(body);
    
    //set current page to vf
    PageReference PageReference = Page.UploadCSVControllerPage; 
    test.setCurrentPage(PageReference);
    //pass in id from blob to idInputFile
    
    UploadCSVController controllerInstance = new UploadCSVController();
    // Then call the instance method
    controllerInstance.fileBody = filebody;
    controllerInstance.fileSize = 502;
    controllerInstance.fileName = OUTPUT_DOCUMENT_NAME;
    controllerInstance.ReadFromFile();
    controllerInstance.save();
} 

static testmethod void testfileupload2(){
    
    String OUTPUT_DOCUMENT_NAME = 'Test File.xls';
    String body = 'LastName,FirstName,Company,Title,LeadSource,Email, STORE_Verified__c, Targeted__c, Description\n '+
        'me,Test,Test Company ,CEO,Other,[email protected],TRUE, 12/01/2022, This is a long text description. Please take a look and then tell us if this has passed.\n' +
        'you,Test,Test Company ,CIO,Other,[email protected],TRUE, 12/01/2022, This is a long text description. Please take a look and then tell us if this has passed.\n' +
        'Us,Test,Test Company ,CTO,Other,[email protected],TRUE, 12/01/2022, This is a long text description. Please take a look and then tell us if this has passed.\n' +
        'tester5,Test,Test Company ,CXO,Other,[email protected],TRUE, 12/01/2022, This is a long text description. Please take a look and then tell us if this has passed.\n' +
        'tester1,Test,Test Company ,COO,Other,[email protected],TRUE, 12/01/2022, This is a long text description. Please take a look and then tell us if this has passed.\n' +
        'tester2,Test,Test Company ,CSO,Other,[email protected],TRUE, 12/01/2022, This is a long text description. Please take a look and then tell us if this has passed.\n' +
        'tester3,Test,Test Company ,"Vp, Technology",Other,[email protected],TRUE, 12/01/2022, This is a long text description. Please take a look and then tell us if this has passed.\n' +
        'tester4,Test,Test Company ,"VP, Clicent Success",Other,[email protected],TRUE, 12/01/2022, This is a long text description. Please take a look and then tell us if this has passed.';
    Blob fileBody = Blob.valueOf(body);
    
    //set current page to vf
    PageReference PageReference = Page.UploadCSVControllerPage; 
    test.setCurrentPage(PageReference);
    //pass in id from blob to idInputFile
    
    UploadCSVController controllerInstance = new UploadCSVController();
    // Then call the instance method
    controllerInstance.fileBody = filebody;
    controllerInstance.fileSize = 502;
    controllerInstance.fileName = OUTPUT_DOCUMENT_NAME;
    controllerInstance.ReadFromFile();

}

static testmethod void testfileupload3(){

    String OUTPUT_DOCUMENT_NAME = 'Test File.csv';
    String body = 'LastName,FirstName,Company,Title,LeadSource,Email, STORE_Verified__c, Targeted__c, Description\n '+
        'me,Test,Test Company ,CEO,Other,[email protected],TRUE, 12/01/2022, This is a long text description. Please take a look and then tell us if this has passed.\n' +
        'you,Test,Test Company ,CIO,Other,[email protected],TRUE, 12/01/2022, This is a long text description. Please take a look and then tell us if this has passed.\n' +
        'Us,Test,Test Company ,CTO,Other,[email protected],TRUE, 12/01/2022, This is a long text description. Please take a look and then tell us if this has passed.\n' +
        'tester5,Test,Test Company ,CXO,Other,[email protected],TRUE, 12/01/2022, This is a long text description. Please take a look and then tell us if this has passed.\n' +
        'tester1,Test,Test Company ,COO,Other,[email protected],TRUE, 12/01/2022, This is a long text description. Please take a look and then tell us if this has passed.\n' +
        'tester2,Test,Test Company ,CSO,Other,[email protected],TRUE, 12/01/2022, This is a long text description. Please take a look and then tell us if this has passed.\n' +
        'tester3,Test,Test Company ,"Vp, Technology",Other,[email protected],TRUE, 12/01/2022, This is a long text description. Please take a look and then tell us if this has passed.\n' +
        'tester4,Test,Test Company ,"VP, Clicent Success",Other,[email protected],TRUE, 12/01/2022, This is a long text description. Please take a look and then tell us if this has passed.';
    
    Blob fileBody = Blob.valueOf(body);
    
    //set current page to vf
    PageReference PageReference = Page.UploadCSVControllerPage; 
    test.setCurrentPage(PageReference);
    //pass in id from blob to idInputFile
    
    UploadCSVController controllerInstance = new UploadCSVController();
    // Then call the instance method
    controllerInstance.fileBody = filebody;
    controllerInstance.fileSize = 502;
    controllerInstance.fileName = OUTPUT_DOCUMENT_NAME;
    controllerInstance.ReadFromFile();
    controllerInstance.save();
}
}
1
  • The testmethod keyword is deprecated, and you should be using the @isTest annotation instead. Yes, it gets used for both the top level class as well as the methods that execute the actual tests.
    – Derek F
    Commented Dec 1, 2022 at 0:48

1 Answer 1

1

ReadFromFile() is an instance method, not a static method (because the method does not have the static keyword in its definition).

To call instance methods, you need an instance of your class.

So the following is wrong

// <ClassName>.<methodName> is how static methods are called
UploadCSVController.ReadFromFile();

and needs to be replaced with

// Create an instance using the "new" keyword
UploadCSVController controllerInstance = new UploadCSVController();
// Then call the instance method
controllerInstance.ReadFromFile();

You will, of course, still need to set the instance variables/properties appropriately so that your code can run. That is part of the "set up test data" phase of unit testing.

6
  • Thanks for that @Derek . Since we are building this as a CSV file are we not able to just call that inside the ReadFromFile Method Commented Dec 1, 2022 at 0:49
  • @JoshAnderson Can you please elaborate? The question you've asked doesn't make sense (or at least I don't have enough context to make sense of it).
    – Derek F
    Commented Dec 1, 2022 at 0:51
  • We built the content version to build out the CSV. First part of the test method does this (or at least this is what I was trying to do). Then once we start the test we are wanting to use the readfromfile method to make sure that the csv is viable, then insert the records with the save method. If I am not taking the correct approach to this test class then please let me know. High level is trying to create a csv in the test method and then act like we are hitting upload, then hitting save. Commented Dec 1, 2022 at 0:54
  • @JoshAnderson The unit test doesn't really use/invoke the Visualforce page itself (that'd be more in the realm of functional testing with a tool like Selenium). All you're looking to do here is execute the (publicly visible) methods in UploadCSVController directly. To that end, creating/inserting the ContentVersion is not really accomplishing much. The action="{!save}" in your VF page should probably be action="{!ReadFromFile}". Testing the "save" button here amounts to creating a UploadCSVController instance, setting fileBody, fileSize, etc... and then calling ReadFromFile().
    – Derek F
    Commented Dec 1, 2022 at 1:12
  • Also, don't forget to gather results and make assertions. That's the 3rd and final (and I'd argue the most important) part of unit testing. 1) Set up test data so your code executes a chosen path. 2) Call the method being tested. 3) Gather results and make assertions.
    – Derek F
    Commented Dec 1, 2022 at 1:16

You must log in to answer this question.

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