Skip to content

Instantly share code, notes, and snippets.

@codefriar
Last active January 6, 2017 13:54
Show Gist options
  • Save codefriar/16ffb954983389cf320ea92fcb3d7a01 to your computer and use it in GitHub Desktop.
Save codefriar/16ffb954983389cf320ea92fcb3d7a01 to your computer and use it in GitHub Desktop.
public with sharing class ExampleCode {
public class exampleCodeException extends Exception {}
Public Integer add(Integer one, Integer two){
return one + two;
}
Public Decimal divide(Integer one, Integer two){
if(two == 0){
throw new exampleCodeException('Dividing by Zero makes Astro Cry');
}
return one / two;
}
Public Decimal getBankAccount(Account a){
return a.SuperSecretBankAccountNum__c;
}
Public Decimal getBankAccountThrowsException(Account a){
if(a.SuperSecretBankAccountNum__c == null){
throw new exampleCodeException('User has no access to this field');
}
return a.SuperSecretBankAccountNum__c;
}
}
/**
* Created by kpoorman on 9/22/16.
* This example test class demonstrates best practices for unit testing in the following scenarios:
* * Postive Unit tests where valid input results in valid output
* * Negative Unit tests where invalid input correctly results in the proper exception being thrown
* * User permission Positive and Negative tests
*
* Prerequisites:
* In order for these tests to pass, the following metadata must be in the org.
* * a custom field, 'SuperSecretBankAccountNum__c' that is a number(18,0) field on Account
* * two custom profiles: 'Trailblazer' and 'Sith'
* ** Trailblazer should have permission to see SuperSecretBankAccountNum__c
* ** Sith should not
* * Additionally, you'll need to install the epically awesome TestFactory from here: https://github.com/dhoechst/Salesforce-Test-Factory
*/
@IsTest
private class ExampleCode_Tests {
// Positive Test - Valid input results in valid results.
@isTest static void test_Add_Postive() {
// TEST SETUP
// No sObjects are needed to test this code. we'll be using hardcoded Integers.
exampleCode astro = new exampleCode();
// Call Test.startTest() to reset governor limits and isolate the code being tested.
Test.startTest();
// Invoke the code being tested,
Integer testValue = astro.add(5,7);
// Call Test.stopTest() to end the isolation of the tested code and re-establish governor limits.
Test.stopTest();
// Make an Assertion to verify that our valid input of 5 and 7, resulted in a correct response of 12.
// Note that this assertEquals has a third parameter, a string that provides a useful developer message
// about what was expected and what was returned.
System.assertEquals(12, testValue, 'Expected 5+7 to equal 12');
}
// Positive unit test for divide method. Given a valid set of integers, the result should be 1/1
@isTest static void test_Divide_Positive() {
//Create Test data and objects
exampleCode Cloudy = new exampleCode();
// Call Test.StartTest to isolate the code being tested.
Decimal result;
Test.startTest();
// Call our code with bad data that *should* cause an exception to occur.
result = Cloudy.divide(1, 1);
// Call Test.stopTest() to end the isolation of the tested code and re-establish governor limits.
Test.stopTest();
// Assert that the boolean is true, and leave a friendly developer message.
System.assertEquals(result, 1.0, 'Expected 1 divided by 1 to be 1');
}
// Negative Unit test - Tests that Exceptions are thrown when bad data is passed into the Unit
// In this case, we're verifying that a divide by zero error is prevented and a custom exception
// is thrown.
@isTest static void test_Divide_Negative() {
//Create Test data and objects
exampleCode Reid = new exampleCode();
// Create a boolean to track whether or not an exception was caught.
Boolean didCatchProperException = false;
// Call Test.StartTest to isolate the code being tested.
Test.startTest();
// Wrap the tested code execution in a try/catch so that we can *catch* the exception we expect
Try {
// Call our code with bad data that *should* cause an exception to occur.
Reid.divide(1, 0);
// Here we catch the exact type of exception we expect the code to have thrown.
} catch (ExampleCode.ExampleCodeException AwesomeException){
// if the proper exception was caught, then we set our boolean as true;
didCatchProperException = true;
}
// Call Test.stopTest() to end the isolation of the tested code and re-establish governor limits.
Test.stopTest();
// Assert that the boolean is true, and leave a friendly developer message.
System.assert(didCatchProperException, 'Expected code to throw an ExampleCode.ExampleCodeException when divisor is 0');
}
// A user permission test follows the Positive or Negative pattern, but runs the code as a user
// with a specific set of perissions (perm set or profile based);
// in this test we'
@isTest static void test_UserProfileHasAccessToGetBankAccount_Positive() {
//Create Test data and objects
exampleCode exCodeMachina = new exampleCode();
// generate a user for testing this code. in this case we're creating a user with a given profile
User u = getUserWithProfile('Standard User');
// Also create an Account. In this case I'm using the test factory.
Account a = (Account)TestFactory.createSObject(new Account());
// set the bank account number to a known state.
a.SuperSecretBankAccountNum__c = 1234567890;
// Create a decimal result.
Decimal result;
// This is the crucial part for a user permission test.
// System.runAs runs the code inside it's block as the user thats passed in. In this case
// we'll be running the code with the user we created above with the profile 'Standard User'
System.runAs(u){
// We'll start the test here
Test.startTest();
// Execute the unit of code.
result = exCodeMachina.getBankAccount(a);
// Stop the test.
Test.stopTest();
}
// Make the assertion that it's working correctly.
System.assertEquals(result, 1234567890, 'Expected this Trailblazers to have access to bank # by profile');
}
// This is another example of a positive test, but in this case we're counting on the user not having access
// to the field in question -- this results in a NULL value for the field.
@isTest static void UserProfileHas_No_AccessToGetBankAccount_Positive() {
exampleCode exCodeMachina = new exampleCode();
User u = getUserWithProfile('Chatter Free User');
Account a = (Account)TestFactory.createSObject(new Account());
Decimal result;
System.runAs(u){
Test.startTest();
result = exCodeMachina.getBankAccount(a);
Test.stopTest();
}
System.assertEquals(result, null, 'Expected Sith lords to be blocked');
}
// In this negative test we'll be calling a different method, one we've coded to throw an error rather than a null value.
// Notice how it follows the general pattern for negative unit tests with the addition of running as a user.
@IsTest static void UserProfileHas_No_AccessToGetBankAccount_Negative() {
// generate a user for testing this code. in this case we're creating a user with a given profile
User u = getUserWithProfile('Chatter Free User');
// Also create an Account. In this case I'm using the test factory.
Account a = (Account)TestFactory.createSObject(new Account());
// set the bank account number to a known state.
a.SuperSecretBankAccountNum__c = 1234567890;
insert a;
Boolean ProperExceptionCaught;
// We'll start the test here
Test.startTest();
exampleCode exCodeMachina = new exampleCode();
exCodeMachina.getBankAccountThrowsException(a);
System.runAs(u){
Try {
//Create Test data and objects
exCodeMachina.getBankAccountThrowsException(a);
} Catch(ExampleCode.ExampleCodeException e){
if(e.getMessage() == 'User has no access to this field'){
ProperExceptionCaught = true;
}
}
}
// Stop the test.
Test.stopTest();
// Make the assertion that it's working correctly.
// System.assert(ProperExceptionCaught, 'Expected this Trailblazers to have access to bank # by profile');
}
// Helper methods that would normally live in their own class but are here for example sake.
private static User getUserWithProfile(String profileName){
Integer uniq = Crypto.getRandomInteger();
User u = new User(
ProfileId = [SELECT Id FROM Profile WHERE Name = :profileName].Id,
LastName = 'last' + uniq ,
Email = 'testUser'+uniq+'@example.com',
Username = 'testUser'+uniq+'@example.com',
CompanyName = 'TEST',
Title = 'title',
Alias = 'alias',
TimeZoneSidKey = 'America/Los_Angeles',
EmailEncodingKey = 'UTF-8',
LanguageLocaleKey = 'en_US',
LocaleSidKey = 'en_US');
insert u;
return u;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment