-5

I am referring the source code from the link: Unable to upload the xlsx file using Apex and Visualforce, why? . How we can write the test classes for it ?

ImportDataFromCSVController

public class ImportDataFromCSVController {
    private static final String errorMesg = 'An error has occured while importin data Please make sure input csv file is correct';

    public Blob csvFileBody {get; set;}
    public string csvAsString {get;set;}
    public String[] csvFileLines {get;set;}
    public List<account> acclist {get;set;}

    public ImportDataFromCSVController(){
        csvFileLines = new String[]{};
        acclist = New List<Account>(); 
    }

    public void importCSVFile(){
        try{
            csvAsString = csvFileBody.toString();
            csvFileLines = csvAsString.split('\n'); 

            for(Integer i=1; i < csvFileLines.size(); i++){
                    Account acct = new Account();
                    string[] csvRecordData = csvFileLines[i].split(',');
                    acct.name = csvRecordData[0] ;             
                    acct.accountnumber = csvRecordData[1];
                    acct.Type = csvRecordData[2];
                    acct.AccountSource = csvRecordData[3];   
                    acct.Industry = csvRecordData[4];                                                                             
                    acclist.add(acct); 
                }
            }catch (Exception e){
                ApexPages.Message errorMessage = new ApexPages.Message(ApexPages.severity.ERROR,errorMesg);
                ApexPages.addMessage(errorMessage);
            } 
        }
    }

I have write the test class for below, it only covers 52%

@isTest
public class ImportDataFromCSVControllerTest {

    static testmethod void testfileupload(){
        Test.startTest();
        String csvFileBody = 'Name,AccountNumber,Type,Accountsource,Industry\r\n,Esha Patharabe,10001,Prospect,Test,Banking\r\n,Trupti Nimje,10002,Prospect,Test,Banking';
    Blob csvBlobData = Blob.valueOf(csvFileBody);
        ImportDataFromCSVController importData = new ImportDataFromCSVController();
        importData.importCSVFile();
        Test.stopTest();
    }
}

Here is the code coverage:

enter image description here

===========================================================

As I dont have option to add solution, hence adding solution as a part of the question only.

@isTest
public class ImportDataFromCSVControllerTest {
    static String str = 'Name,AccountNumber,Type,Accountsource,Industry\n Esha Patharabe,10001,Prospect,Test,Banking\n Trupti Nimje,10002,Prospect,Test,Banking';       

    public static String[] csvFileLines;
    public static Blob csvFileBody;

    static testmethod void testfileupload(){
        Test.startTest();       
        csvFileBody = Blob.valueOf(str);
        String csvAsString = csvFileBody.toString();
        csvFileLines = csvAsString.split('\n'); 

        ImportDataFromCSVController importData = new ImportDataFromCSVController();
        importData.csvFileBody = csvFileBody;
        importData.importCSVFile();
        Test.stopTest();
    } 

    static testmethod void testfileuploadNegative(){
        Test.startTest();       
        csvFileBody = Blob.valueOf(str);
        String csvAsString = csvFileBody.toString();
        csvFileLines = csvAsString.split('\n'); 

        ImportDataFromCSVController importData = new ImportDataFromCSVController();
        importData.importCSVFile();
        Test.stopTest();
    }
}

and code coverage is 100%

enter image description here

  • 3
    I haven't downvoted this question, but my guess would be that you got the downvote from lack of research (and maybe also because your test method contains no assertions). You also haven't provided any indication of which lines are and which lines aren't currently covered by your test. There are many, many questions here asking about writing tests as well. My last talking point here is that your comment can be interpreted to have an aggressive tone (which may discourage people from trying to help). – Derek F May 24 '17 at 19:13
  • @DerekF Sound assessment and I have removed the offending comment. – Adrian Larson May 24 '17 at 20:17
  • If you have a specific question or are stuck on a specific issue then narrow the question to that issue and the community will reopen – Eric May 25 '17 at 5:42
  • You still don't have any assertions. Verifying that your code works as you expect it to work is the most important part of unit testing. It’s also one of the things that Force.com developers commonly neglect. Unit tests that do not verify the results of the code aren’t true unit tests. They are commonly referred to as smoke tests, which aren’t nearly as effective or informative as true unit tests. -How to Write Good Unit Tests – Adrian Larson Jun 12 '17 at 13:26
3

The question "How do I write a test for/get more coverage for X?" is a pretty common one, and has numerous variations.

The refrain that you'll read over and over is that code coverage is not the primary goal of unit testing, ensuring that your code produces expected output for different inputs is. If you test a sufficient number of possible inputs for each publicly accessible method, the code coverage will follow.

Even though you haven't provided an indication of which lines are and which lines aren't covered, I feel very confident that the following lines are not being covered.

// These lines of code should not be getting covered, based on your current test method
csvFileLines = csvAsString.split('\n');

for(Integer i=1; i < csvFileLines.size(); i++){
    Account acct = new Account();
    string[] csvRecordData = csvFileLines[i].split(',');
    acct.name = csvRecordData[0] ;             
    acct.accountnumber = csvRecordData[1];
    acct.Type = csvRecordData[2];
    acct.AccountSource = csvRecordData[3];   
    acct.Industry = csvRecordData[4];                                                                             
    acclist.add(acct); 
}

Why am I so confident? Because your current test method doesn't provide your class with a CSV file to parse. No CSV file means that csvAsString = csvFileBody.toString(); is probably giving you a NullPointerException that kicks you into your catch block. Even if that weren't the case, no CSV file means that csvFileLines.size() returns 0. 0 is less than 1, so you never execute the code inside of your loop.

No execution = no coverage.

Fixing this particular unit test of yours will mean that you need to, in your test method, create data to act as your test "CSV" file, and assign it to your csvFileBody member variable before calling importCSVFile(). You'll probably create this as a String, which doesn't match the Blob type of your member variable...but I'll leave tackling that problem to you.

The larger theme to realize here is that only code that is executed by a unit test is counted as "covered", and to execute a particular piece of code in a test you need to identify which conditions will lead to a piece of code being executed and ensure that you set up the appropriate data to create those conditions. In this case, the condition is "csvFileBody has at least 2 lines of CSV-formatted data in it"

Another realization that I hope you'll come to is that by fixing this one unit test, you'll lose some of the coverage that you used to have (assuming your test "CSV" data is properly formatted for the class you're testing, you'd lose coverage for the catch block).

The "fix" for that is to have more than one unit test that is specifically testing importCSVFile(). Having properly formatted data stored in csvFileBody before calling your method is an example of a "positive" test case. Your current test, which has no data stored in csvFileBody is a "negative" test case (i.e. your input is not what you would typically expect, and may cause issues with the class you're testing).

Testing multiple cases, both positive and negative, is a best practice.

The final thing I'll talk about here is making assertions.

Assertions are how you actually "test" your code, making sure that your output matches your expectations. If you don't make assertions, it is very difficult to ensure that your code is behaving the way you think it should be for all but the most simple code.

Someone could, in the future, change your code so that the result of 2 + 2 would be 5. Accidents that obvious don't really happen (or at least I hope they don't...), but more subtle accidents are virtually guaranteed in systems of nearly any complexity. Assertions are what shields you from such accidents.

For your positive case, good things to make assertions against would be: - The number of Account records you end up with in acclist matches the number of Accounts in your test "CSV" file (probably csvFileLines.size() - 1) - The data in each "column" of your test "CSV" file was stored in the field on Account that you expected them to be in

For your negative case, a good thing to make an assertion against would be that the page messages contain the same error message as the one you defined in your private static final String errorMesg (you might want to add the @testVisible annotation to make it easier to grab the exact error message to assert against).

  • @user4567570 A CSV file is nothing more than a simple string (with commas and newlines), so you create it like you would any other string. I will not be showing any code. The point of my answer was to guide you so that you would be able to write better tests yourself. Taking this information, and struggling to make your own tests from it will teach you far more than simply copy/pasting an answer. – Derek F May 25 '17 at 12:54
  • Also, ye anonymous downvoter out there, care to explain? – Derek F May 25 '17 at 12:55

Not the answer you're looking for? Browse other questions tagged or ask your own question.