Last active
April 14, 2021 18:14
-
-
Save niavesper/59e0cdbfe02fb8609b672bfd3a3c3bab to your computer and use it in GitHub Desktop.
RecipeHandler2.cls: First method throws an error when one of the key fields is blank, which is the requirement of Week 6 homework. RecipeHandler2_Test contains testing for exception throwing: positive (lines 25-93) and negative (lines 178-223). RecipeTrigger2.trigger calls on the exception-throwing method
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
public with sharing class RecipeHandler2 { | |
// Week 6 homework: Exception Testing | |
public static void throwException(List<Recipe__c> exceptionRecipes){ | |
for (Recipe__c r : exceptionRecipes){ | |
if (r.Name == null || r.Active_Time__c == null || r.Description__c == null || r.Active_Time_Units__c == null || r.Servings__c == null){ | |
r.addError('One of the key ingredients is null!'); | |
} | |
} | |
} | |
public static void rateComplexity(List<Recipe__c> ratedRecipes) { | |
List <Recipe__c> updatedComplexityRecipes = new List <Recipe__c>(); | |
for (Recipe__c r : ratedRecipes){ | |
switch on HelperFunctions.rateRecipeComplexity (r){ | |
when 1 { | |
r.Complexity__c = 'Simple'; | |
} | |
when 2 { | |
r.Complexity__c = 'Moderate'; | |
} | |
when 3 { | |
r.Complexity__c = 'Difficult'; | |
} | |
} | |
updatedComplexityRecipes.add(r); | |
} | |
} | |
public static void createTasks(List<Recipe__c> taskRecipes) { | |
List <Task> newTasks = new List<Task>(); | |
for (Cookbook__c c : [SELECT Id, OwnerId FROM Cookbook__c | |
WHERE ID IN (SELECT Cookbook__c FROM Recipe_Usage__c | |
WHERE Recipe__r.Draft__c = false AND Recipe__r.Id IN : taskRecipes)]){ | |
Task t = new Task(); | |
t.WhatId = c.Id; | |
t.OwnerId = c.OwnerId; | |
t.ActivityDate = Date.Today().addDays(7); | |
t.Subject = 'Review recipe'; | |
t.Status = 'Not Started'; | |
newTasks.add(t); | |
} | |
insert newTasks; | |
} | |
} |
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
@isTest | |
private class RecipeHandler2_Test { | |
@testSetup | |
static void dataCreation(){ | |
// create data for testing recipe Complexity | |
List <Recipe__c> complexityRecipes = new List<Recipe__c>(); | |
for(integer i = 0; i < 3; i++){ | |
Recipe__c r = new Recipe__c( | |
Name = 'Complexity Recipe ' + i, | |
Active_Time__c = i * 30, | |
Active_Time_Units__c = 'Minutes', | |
Servings__c = i + 6, | |
Description__c = 'Test Desc'); | |
HelperFunctions.rateRecipeComplexity (r); | |
complexityRecipes.add(r); | |
} | |
// insert data | |
insert complexityRecipes; | |
} | |
/*** positive testing for before insert of the "throwException" method***/ | |
@isTest | |
static void throwException_InsertPositive(){ | |
// create test data | |
List <Recipe__c> draftRecipes = new List<Recipe__c>(); | |
for(integer i=0; i < 4; i++){ | |
Recipe__c r = new Recipe__c( | |
Name = 'Draft Recipe ' + i, | |
Active_Time__c = i, | |
Description__c = 'Test Description ' + i, | |
Active_Time_Units__c = 'Minutes', | |
Servings__c = i); | |
draftRecipes.add(r); | |
} | |
// assign blank values to key fields: one blank key field per record | |
draftRecipes[0].Active_Time__c = null; | |
draftRecipes[1].Description__c = null; | |
draftRecipes[2].Active_Time_Units__c = null; | |
draftRecipes[3].Servings__c = null; | |
// Insert data and catch exception | |
Test.startTest(); | |
try{ | |
insert draftRecipes; | |
} catch (Exception e) { | |
// assert: the type of error we get should be 'System.DmlException' | |
System.assertEquals(e.getTypeName(), 'System.DmlException'); | |
} | |
Test.stopTest(); | |
} | |
/*** positive testing for before update of the "throwException" method***/ | |
@isTest | |
static void throwException_UpdatePositive(){ | |
List <Recipe__c> draftRecipes = new List<Recipe__c>(); | |
for(integer i=0; i < 4; i++){ | |
Recipe__c r = new Recipe__c( | |
Name = 'Draft Recipe ' + i, | |
Active_Time__c = i, | |
Description__c = 'Test Description ' + i, | |
Active_Time_Units__c = 'Minutes', | |
Servings__c = i); | |
draftRecipes.add(r); | |
} | |
insert draftRecipes; | |
// assign blank values to key fields: one blank key field per record | |
draftRecipes[0].Active_Time__c = null; | |
draftRecipes[1].Description__c = null; | |
draftRecipes[2].Active_Time_Units__c = null; | |
draftRecipes[3].Servings__c = null; | |
// Update data and catch exception | |
Test.startTest(); | |
try{ | |
update draftRecipes; | |
} catch (Exception e) { | |
// assert: the type of error we get should be 'System.DmlException' | |
System.assertEquals(e.getTypeName(), 'System.DmlException'); | |
} | |
Test.stopTest(); | |
} | |
/*** positive testing for before insert of the "rateComplexity" method***/ | |
@isTest | |
static void addComplexityRating_InsertPositive(){ | |
// query ratings of inserted recipes and assign them to strings for assertion | |
String ratingZero = [SELECT Id, Complexity__c FROM Recipe__c WHERE Name = 'Complexity Recipe 0'].Complexity__c; | |
String ratingOne = [SELECT Id, Complexity__c FROM Recipe__c WHERE Name = 'Complexity Recipe 1'].Complexity__c; | |
String ratingTwo = [SELECT Id, Complexity__c FROM Recipe__c WHERE Name = 'Complexity Recipe 2'].Complexity__c; | |
// assert: compare expected values of *inserted* records to actual | |
System.assertEquals('Simple', ratingZero, 'Rating Zero should be "Simple"'); | |
System.assertEquals('Moderate', ratingOne, 'Rating One should be "Moderate"'); | |
System.assertEquals('Difficult', ratingTwo, 'Rating Tw0 should be "Difficult"'); | |
} | |
/*** positive testing for before update of the "rateComplexity" method ***/ | |
@isTest | |
static void addComplexityRating_UpdatePositive(){ | |
// Create a list of inserted recipes | |
List <Recipe__c> recipesUpdatedWithComplexity = [SELECT Id FROM Recipe__c WHERE Name LIKE 'Complexity%' AND Complexity__c != null]; | |
// update data | |
Test.startTest(); | |
update recipesUpdatedWithComplexity; | |
Test.stopTest(); | |
// query ratings of updated recipes and assign them to strings for assertion | |
String ratingZero = [SELECT Id, Complexity__c FROM Recipe__c WHERE Name = 'Complexity Recipe 0'].Complexity__c; | |
String ratingOne = [SELECT Id, Complexity__c FROM Recipe__c WHERE Name = 'Complexity Recipe 1'].Complexity__c; | |
String ratingTwo = [SELECT Id, Complexity__c FROM Recipe__c WHERE Name = 'Complexity Recipe 2'].Complexity__c; | |
// assert: compare expected values of *updated* records to actual | |
System.assertEquals('Simple', ratingZero, 'Rating Zero should be "Simple"'); | |
System.assertEquals('Moderate', ratingOne, 'Rating One should be "Moderate"'); | |
System.assertEquals('Difficult', ratingTwo, 'Rating Two should be "Difficult"'); | |
} | |
/*** positive testing for after update of the "createTasks" method***/ | |
@isTest | |
static void createTasksOnCookbook_UpdatePositive(){ | |
// create and insert test data (new non-draft Recipe and Cookbook). | |
List<sObject> recordsToInsert = new List<sObject>(); | |
recordsToInsert.add (new Recipe__c (Name = 'Task Recipe', | |
Active_Time__c = 2, | |
Active_Time_Units__c = 'Hours', | |
Description__c = 'Test Description', | |
Servings__c = 8 | |
)); | |
recordsToInsert.add (new Cookbook__c (Name = 'Test Cookbook')); | |
insert recordsToInsert; | |
// query newly created records to use their IDs on the record of the junction object | |
Recipe__c newRecipe = [SELECT Id FROM Recipe__c WHERE Name = 'Task Recipe']; | |
Cookbook__c newCookbook = [SELECT Id, OwnerId FROM Cookbook__c]; | |
// create test data (new Recipe Usage with lookups to earlier created Cookbook and Recipe) | |
Recipe_Usage__c newRecipeUsage = new Recipe_Usage__c ( | |
Cookbook__c = newCookbook.Id, | |
Recipe__c = newRecipe.Id); | |
// insert test data | |
insert newRecipeUsage; | |
// update the recipe record | |
Test.startTest(); | |
update newRecipe; | |
Test.stopTest(); | |
// assign the task that should have been created to a list | |
List<Task> newTasks = [SELECT Id FROM Task | |
WHERE WhatId = : newCookbook.Id AND | |
OwnerId = : newCookbook.OwnerId AND | |
ActivityDate = NEXT_N_DAYS:7 AND | |
Subject = 'Review recipe' AND | |
Status = 'Not Started' | |
]; | |
// assert: check to see if there is one task on the list that meets the conditions | |
System.assertEquals(1, newTasks.size(), 'One task should have been inserted'); | |
} | |
/*** negative testing for before insert of the "throwException" method***/ | |
@isTest | |
static void throwException_InsertNegative(){ | |
List <Recipe__c> draftRecipes = new List<Recipe__c>(); | |
for(integer i=0; i < 4; i++){ | |
Recipe__c r = new Recipe__c( | |
Name = 'Draft Recipe ' + i, | |
Active_Time__c = i, | |
Description__c = 'Test Description ' + i, | |
Active_Time_Units__c = 'Minutes', | |
Servings__c = i); | |
draftRecipes.add(r); | |
} | |
Test.startTest(); | |
insert draftRecipes; | |
Test.stopTest(); | |
// assert: the type of error we get should be 'System.DmlException' | |
System.assertEquals(4, draftRecipes.size(), '4 recipes should have been inserted without error'); | |
} | |
/*** negative testing for before update of the "throwException" method***/ | |
@isTest | |
static void throwException_UpdateNegative(){ | |
List <Recipe__c> draftRecipes = new List<Recipe__c>(); | |
for(integer i=0; i < 4; i++){ | |
Recipe__c r = new Recipe__c( | |
Name = 'Draft Recipe ' + i, | |
Active_Time__c = i, | |
Description__c = 'Test Description ' + i, | |
Active_Time_Units__c = 'Minutes', | |
Servings__c = i); | |
draftRecipes.add(r); | |
} | |
insert draftRecipes; | |
Test.startTest(); | |
update draftRecipes; | |
Test.stopTest(); | |
// assert: the type of error we get should be 'System.DmlException' | |
System.assertEquals(4, draftRecipes.size(), '4 recipes should have been inserted without error'); | |
} | |
/*** Negative testing for after update of the "createTasks" method ***/ | |
@isTest | |
static void createTasksOnCookbook_UpdateNegative(){ | |
// create and insert test data (new draft Recipe and Cookbook). | |
List<sObject> recordsToInsert = new List<sObject>(); | |
recordsToInsert.add (new Recipe__c (Name = 'Task Recipe', | |
Active_Time__c = 2, | |
Active_Time_Units__c = 'Hours', | |
Description__c = 'Test Description', | |
Servings__c = 8, | |
Draft__c = True | |
)); | |
recordsToInsert.add (new Cookbook__c (Name = 'Test Cookbook')); | |
insert recordsToInsert; | |
// query newly created records to use their IDs on the record of the junction object | |
Recipe__c newRecipe = [SELECT Id FROM Recipe__c WHERE Name = 'Task Recipe']; | |
Cookbook__c newCookbook = [SELECT Id, OwnerId FROM Cookbook__c]; | |
// create test data (new Recipe Usage with lookups to earlier created Cookbook and Recipe) | |
Recipe_Usage__c newRecipeUsage = new Recipe_Usage__c ( | |
Cookbook__c = newCookbook.Id, | |
Recipe__c = newRecipe.Id); | |
// insert test data | |
insert newRecipeUsage; | |
// update the recipe record | |
Test.startTest(); | |
update newRecipe; | |
Test.stopTest(); | |
// assign the task that should have been created to a list | |
List<Task> newTasks = [SELECT Id FROM Task | |
WHERE WhatId = : newCookbook.Id AND | |
OwnerId = : newCookbook.OwnerId AND | |
ActivityDate = NEXT_N_DAYS:7 AND | |
Subject = 'Review recipe' AND | |
Status = 'Not Started' | |
]; | |
// assert: check to see if there is one task on the list that meets the conditions | |
System.assertEquals(0, newTasks.size(), 'No tasks should have been inserted'); | |
} | |
} |
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
trigger RecipeTrigger2 on Recipe__c (before insert, after insert, before update, after update) { | |
if (trigger.isBefore && ( trigger.isInsert || trigger.isUpdate)){ | |
RecipeHandler2.throwException(trigger.new); | |
RecipeHandler2.rateComplexity(trigger.new); | |
} | |
if(trigger.isAfter && trigger.isUpdate){ | |
RecipeHandler2.createTasks(trigger.new); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I think except the naming of positive/negative this looks good! 👏 Negative testing is when catching the unexpected situation, bad values etc, like error messages the way you added with addError. I know this sounds a bit counterproductive as that exception is expected but well 😄 Good job @niavesper
Negative tests verify that your code handles exceptions and errors well
Testing Unexpected Conditions
Bad Input Values
Boundary Conditions
Let me know if you have question on positive/negative testing.