Skip to content

Instantly share code, notes, and snippets.

@AlwaysThinkin
Last active January 30, 2023 06:58
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AlwaysThinkin/c3551cb22bd48b905e5a5bc153177e58 to your computer and use it in GitHub Desktop.
Save AlwaysThinkin/c3551cb22bd48b905e5a5bc153177e58 to your computer and use it in GitHub Desktop.
/* This Apex Class is a Unit Test Class and all the code can be checked by running the test.
* Copy this into a new Apex Class named "ControlFlow" and save it.
* As you read through it, look for "FIX ME!" and make the changes suggested.
* If your changes are correct all the tests (System Asserts) will pass.
*
* You can also see what's happening in the Logs by opening a Log and checking the Debug Only box
* you can compare the line numbers in the Log to the line number in the Class to find a specific
* debug entry.
*/
@isTest
public class ControlFlowAnswers {
static testMethod void logic(){
//IF statements. These are just like Workflow Rules.
if(true){
//And here is your Workflow Action in between the curly brackets
System.debug('Do Something!');
}
//you can condense it to one line if there's only one action.
if(true) System.debug('Still do something');
//prep a true/false variable for the next step.
Boolean myBool = false;
//use "else" when you only want the action to happen when your if case is false
//This is what Workflow Rules can't do: actions for multiple results from one rule
if(myBool){
System.debug('The Boolean was true');//only runs if myBool is true
} else {
System.debug('The Boolean was false');//only runs if myBool is false
}
System.debug('The Boolean doesn\'t matter here');//This line will always run
//you can string multiple condition cases with "else if"
if(myBool){
System.debug('The Boolean was: ' + myBool);
} else if(!myBool){
System.debug('The Boolean was: ' + myBool);
} else {
System.debug('Whoa! there was no value');
}
//FIX ME!: Try changing myBool to false and confirm that the conditions cascade to the next condition
//FIX ME!: Try not setting myBool to any value and see what happens...
//And just so you know it exists, there is the ternary operator for if-else statements
//This has to be used with variable assignment, so it's use is limited but elegant
//Here, we set a String of "true" or "false" depending on the Boolean value
String theAnswer = ((myBool == null) ? 'true' : 'false');
//FIX ME!: Google "Apex Boolean Methods" to find how to convert the String named theAnswer to a Boolean
//and then assert that myBool equals theAnswer.
//Hint: Since we cannot directly compare a String to a Boolean, you have to create a new Boolean "b" with the conversion.
Boolean b = boolean.valueOf(theAnswer);
System.assertEquals(b, myBool);
//Most of the time we're comparing two things in our conditions
//You have to get used to typing "==" when you think "equals" in conditions
if(theAnswer.length() == 4){
System.debug('exactly 4 characters long');
} else if(theAnswer.length() >= 5){
System.debug('longer than 5 characters');
}
//FIX ME!: Now that you know about using "==" to compare values,
//rewrite this conditional block to accomodate null values.
String myPicklist = 'up';
if(myPicklist == 'up'){
System.debug('The value is up');
System.assertEquals('up', myPicklist);
} else if(myPicklist == 'down'){
System.debug('The value is down');
System.assertEquals('down', myPicklist);
} else if(myPicklist == ''){
System.debug('The picklist was empty');
System.assert(String.isEmpty(myPicklist));//Can you find an Apex String method to test if a string is null?
} else {
System.debug('The value was neither up nor down nor null');//what do you have to set myPicklist to to get this result?
System.assert((myPicklist != 'up' && myPicklist != 'down' && !String.isEmpty(myPicklist))); //How would you test that the string is not 'up', 'down' or null?
}
//Any method that returns a boolean can be used in the condition clause.
//With Maps, a common pattern is to check for a value's existence before getting the value,
//and if it's not there, put it in the Map.
//prep a Map first so we have something to work with.
Map<String, Decimal> metricMap = new Map<String, Decimal>{'Kilo' => 1000, 'Milli' => .001};
if(metricMap.containsKey('Mega')){
System.debug('Mega is already there!');
System.debug(metricMap.get('Mega'));
} else {
metricMap.put('Mega', 1000000);
}
System.assertEquals(metricMap.get('Mega'), 1000000);
//FIX ME!: Add "Micro" to the metricMap so the following System Assert passes
if(metricMap.containsKey('Micro')){
System.debug('Micro is already there!');
} else {
metricMap.put('Micro', .000001);
}
System.assertEquals(.000001, metricMap.get('Micro'));
//let's prep some Booleans to play with comparison operators
Boolean x = true;
Boolean y = false;
//Conditionals can contain chains of variables (or boolean methods).
//Comparison operators follow the rules of logic you use everyday in Reports, Views and Formulas
if(x && y) System.debug('True AND False evaluates to False');
if(x && !y) System.debug('True AND NOT False evaluates to True');
if(x || y) System.debug('True OR False evaluates to True');
if(!x || y) System.debug('Not True OR False evaluates to False');
if(!(x && y)) System.debug('True AND False evaluates to False, BUT we re-evaluate that cumulative False to True with NOT(!)');
//FIX ME! Add in a third Boolean "z" to get these conditions to be true
Boolean z = true;
if((x && y) || z) System.debug('Now it evaluates to True!');
if(!x || y || z) System.debug('Now it evaluates to True!');
////////////////
// FOR LOOPS //
////////////////
//For Loops allow you to work with multiple variables or objects
//There wasn't a good equivalent in the UI until Process Builder came along
//In Apex, they are an essential control for, well, everything!
//First variation: For each item in a List or Set, do something
Set<String> metricSet = metricMap.keySet();//Remember these are: ['Mega', 'Micro', 'Milli']
for(String s : metricSet){//for every string in metricSet do something...
System.debug(s);
}
//FIX ME! Now that we've looped through the keys in metricSet, loop through the values
List<Decimal> metricValues = metricMap.values();
for(Decimal d : metricValues){
system.debug(d);
}
//Second variation: for each record returned by a SOQL query, do something.
for(User u : [Select Name from User]){
System.debug(u.Name);
}
//FIX ME! Write a for loop that retreive all the Profile Names and prints them in a System Debug
//Note that in Unit Tests without SeeAllData = True, Users and Profiles are still accessible along with a few other special Objects
for(Profile p : [Select Name from Profile]){
System.debug(p.Name);
}
//Third variation: repeat the loop as many times as instructed
//This uses a special format common to many languages of establishing:
//1. An Entry Condition: Integer i = 0 (arbitrary, but 0 is useful when working with list indices)
//2. A Comparison: i < 5 (means "as long as")
//3. An Incrementor: i++ (add 1 to i each loop)
for(Integer i = 0 ; i < 5 ; i++){
System.debug('i now equals: ' + i);
}
List<String> names = new List<String>{'Dave', 'Jim', 'Sara', 'George'};
String d = names[0];
//A very frequent pattern is repeating the loop for each item in a list using the list.size() method
for(Integer i = 0; i < names.size(); i++){
System.debug('Value at index ' + i + ' is ' + names[i]);//we can use i to retrieve each item in the list in order
}
//FIX ME! Make a for loop of 5 Integers that adds each Integer to itself
//use a system debug to output the result like "1 + 1 = 2"
//you have to use 3 variations on + to do this:
//1. + to concatentate two items
//2. + as a string to print out the plus sign (and later the equals sign)
//3. + as a mathematical operator to add the two Integers
for(Integer i = 0; i < 5 ; i++){
Integer j = i + i;
System.debug(i + ' + ' + i + ' = ' + j);
}
//Loop-di-Loop. You can embed loop within loops.
//prep some units of measurement
List<String> units = new List<String>{'meter', 'watt', 'gram'};
//The first iteration will loop through all the values in the inner loop first
//and then proceed on to the next item in the outer loop
for(String u : units){
for(String m : metricMap.keySet()){
System.debug('A ' + m + u + ' is ' + metricMap.get(m) + u + 's');//We use m to get the string and the metric multiplier from the Map!
}
}
//FIX ME! BIG CHALLENGE!!!
//Let's revise the FIX ME challenge from our SOQL lesson to use loops
//1. Create a Query to get all Contacts that are missing both a phone number and email address
List<Contact> conAccts = [SELECT Id, FirstName, LastName, Name, Phone, CleanStatus, Account.Phone
FROM Contact
WHERE Phone = null AND Email = Null];
//2. Create an empty collection to hold records we want to update
Map<Id, Contact> contactsToUpdateMap = new Map<ID, Contact>();
//3. Set the Contacts' Phone Number to the Account's Phone Number
for(Integer i = 0 ; i < conAccts.size() ; i++){
conAccts[i].Phone = conAccts[i].Account.Phone;
}
//4. Put the records into your update collection
//we have to add records to our collection
for(Integer i = 0 ; i < conAccts.size() ; i++){
contactsToUpdateMap.put(conAccts[i].Id, conAccts[i]);
}
//5. Now, since we don't know the email, let's set CleanStatus to 'Skipped'
for(Integer i = 0 ; i < conAccts.size() ; i++){
conAccts[i].CleanStatus = 'Skipped';
}
//6. Put the records into your update collection
//Note that we're adding records again! Be careful!
for(Integer i = 0 ; i < conAccts.size() ; i++){
contactsToUpdateMap.put(conAccts[i].Id, conAccts[i]);
}
//7. Use an "update" call to save the changes and commit them to the database
update contactsToUpdateMap.values();
//8. Write a Unit Test to confirm it worked!
// Test that there is now a phone number, and that phone number matches the account
// Test that the CleanStatus field is "Skipped"
List<Contact> updatedContacts = [SELECT CleanStatus, Account.Phone, Phone FROM Contact WHERE Id IN :contactsToUpdateMap.keySet()];
for(Contact c : updatedContacts){
System.AssertEquals('Skipped', c.CleanStatus);
System.assertEquals(c.Account.Phone, c.Phone);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment