0

New to Apex so apologies. Previous experience only with triggers, so easy to create scenario to trigger change. Picked up having to write test class but not sure how to go about it

Assuming I need to validate that new case created (not sure how) and cs.Origin = 'In Person' (again, not sure how);

I don't know how to create a logical hook which will query the output of the class.

Class below (not my code - fired from a button on VF page )

public class CaseCon {
    @AuraEnabled
    public static Case initCase()
    {
        Case cs = new Case();
        cs.Origin = 'Personal';
        insert cs;
        return cs;
    }
}
4
  • 4
    Welcome to SFSE! Have you gone through the Apex Testing module on trailhead yet? Trailhead is much better suited to learning the first bits of a new concept (like unit testing) than this site is.
    – Derek F
    Dec 11, 2018 at 16:00
  • Yes - my problem is they all rely on doing something to cause the case to happen - i.e. they are basically triggers OR rely on input.
    – Rob Irwin
    Dec 11, 2018 at 16:23
  • Typically, we expect you to make an attempt to solve your problem, then indicate here where specifically you are stuck. Questions asking how to write a unit test where no initial attempt has been made are often voted down and/or closed. "How do I test this code?" is vague and does not demonstrate research effort. "Why does this unit test I wrote behave differently than I expect?" is much more specific and may get high quality answers.
    – Adrian Larson
    Dec 11, 2018 at 16:46
  • Please edit your post with any clarifications. Code does not display well in comments anyway, and many users do not read them.
    – Adrian Larson
    Dec 11, 2018 at 17:13

3 Answers 3

0

You are able to check either the return value of the method or retrieve cases via soql in your Test Environment, as it exists with no awareness of actual data. What I mean, is that when you execute your test, imagine you execute it in empty (almost) org.

So, invoking the following soql: [SELECT Id FROM Case] in your test method will return an empty list, even though there are some cases in your org. So after the beginning of the test invocation, execute your static method and the same soql to retrieve the newly created case.

However, the next method will be executed with no clue of the result of inserted records. To bypass this, use @TestSetup anotation

2
  • Thanks all. Piecing together the logic of suggestions I want to count the number of results from [SELECT Id FROM Case] - expecting 0, then run the initCase, and do a recount, expecting 1? @TestSetup is a revelation - plenty to try out tomorrow.
    – Rob Irwin
    Dec 11, 2018 at 22:43
  • @RobIrwin yep, you got the point. If you'll face problems with testsetup or anything else -- feel free to type in the thread Dec 12, 2018 at 4:52
1

A very broad overview of what a unit test looks like is this:

  1. Set up your test environment (insert records as needed, prepare class variables as needed, etc...) to ensure that the code that you want to execute will be executed
  2. Cause the code you want to test to be executed
  3. Gather the results, and make assertions to verify that the code you're testing did what you expected it to do (Usually involves queries to fetch updated data from the database)

One important point to note here is that in a unit test, we don't really care about how the code being tested will be executed in day-to-day operations. We just care about somehow causing our intended piece of code to be run.

While your initCase() method does have the @auraenabled annotation, that fact doesn't have any effect on how you can execute initCase(). In this case (and in most other cases), this is just another method that can be called anywhere in code; it's no different than, say, String.isBlank() or Math.pow(2,6).

To write a unit test for a trigger, you need to use a DML statement like insert myCase; or update myCase;.
To write a unit test for initCase(), all you need to do is get an instance of CaseCon, and then call the initCase() method.

Simple as that. No special "hooks" are required, and generally speaking, no hooks should be created either. The idea here is that you're trying to test that the output/results of your implementation are correct rather than testing the details of that implementation.

Looking at the class/method that you're testing can help determine what outputs your method produces (return values, changes to the database, changes to class variables, etc...). The unit test, however, should generally not care how we arrived at the result, just that we did arrive at the desired result.

Your output here is a Case being returned from your method, and that Case being inserted into Salesforce.

Unit tests, by default, do not have access to most of the data in the environment (production, or a sandbox of some flavor) that you're running the test in. Test data is isolated by default. This means that if you query for all Case records after executing your target code (initCase()), you should only see the Case record that was inserted by initCase() (plus whatever other Case records you happened to insert in your test prior to running that code, plus whatever other Case records end up being created by triggers on Case or other objects)

My Recommendations

  • You likely don't need to perform any test setup here (Item #1 from the overview of testing) other than making an instance of CaseCon
  • initCase() returns a Case record, you should store this in a variable, and make assertions against it such as
    • Does the returned Case have an Id? (Salesforce updates the in-memory instance of a record with its new Id after the insert DML finishes)
    • Does the returned Case have your expected value in the Origin field?
  • You probably want to run a query to see how many Case records exist prior to running initCase()
  • You probably want to run another query after running initCase() to see how many records exist after initCase() has run
    • Checking that there is one and only one new Case (after.size() - before.size()) is a good idea
    • Checking that the new Case that you queried to make sure that it also has the correct Origin value (that the value is persisted in the database, not just in-memory) is a good idea
0

Just a quick thanks all,. esp being of habits - got complete coverage with the test class below:

A little surprised it didn't want me to validate cs.Origin = 'Personal' but I'll take the win.

Possibly not the most efficent way?

///////////////////////////////////////////////////////////////////////

@isTest public with sharing class CaseCon_UnitTest { @isTest public static void runTest(){

    //count results before   

integer countbefore= database.countQuery('select count() from case');

system.debug('the count before is '+ countbefore);

    //execute initcase
    Casecon.initCase();

integer countafter= database.countQuery('select count() from case');



system.debug('the count after is '+ countafter);


}

}

1
  • Rob, Salesforce doesn't ever MAKE you validate anything. While they do require you to have a certain percentage of code coverage (i.e. at least 75% of your code is run in test classes), it's up to you to to decide what logic needs to be validated as part of your test class.... to ensure that your code is actually doing what it's supposed to do. It's highly recommended to use assertions (e.g. System.assert) in your test class. I would look at these examples for more info: developer.salesforce.com/docs/atlas.en-us.apexcode.meta/… Dec 12, 2018 at 15:31

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.