Last active
January 30, 2023 06:58
-
-
Save AlwaysThinkin/c3551cb22bd48b905e5a5bc153177e58 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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