Recently Salesforce moving towards more meaningful Unit Testing strategy by introducing a brand new APEX Assert Class in Salesforce which is detaching itself from the System Class. From now on Assert Class by own right is going to get its own class. Now everyone is thinking why is this change? I will discuss on that topic and also different use cases where you can use Assert Class.
We all heard about the term “Separation of concern” which is a well known design principle in Software industry.
separation of concerns is a design principle for separating a computer program into distinct sections. Each section addresses a separate concern, a set of information that affects the code of a computer program.
Wiki
Now, if you take a look into System Class, you will realize all sorts of different functionality are clubbed into this giant class. Moreover, the sphere of System Class scatters from Unit Testing (Assert Methods), scheduling, time related functionality and to debugging. So, moving of Assert Class from System Class into its own realm is an exercise to separate a concern into a distinct area. This change is blessing in disguise as now developers can practice it to achieve granular level testing criteria. I am providing you a couple of examples to demonstrate the usage of the Assert Class in Salesforce.
To begin with the setup class. I took this example from the Trailhead and extend it as per the need.
@testSetup
static void dataCreation() {
Account account = TestFactory.getAccount('Muddy Waters Inc.', true);
Contact contact = TestFactory.getContact(account.Id, 'Muddy', 'Waters', true);
Opportunity opp = New Opportunity();
opp.Name = 'Long lost record';
opp.AccountId = account.Id;
opp.CloseDate = Date.today().addDays(14);
opp.StageName = 'Prospecting';
insert opp;
}
Analysis of different Assert statements
Assert.areNotEqual()
Method Signature
public static void areNotEqual(Object notExpected, Object actual, String msg)
Code Sample
@isTest
static void testAreNotEqual() {
Test.startTest();
List<Opportunity> opps = [SELECT Id, AccountId FROM Opportunity];
Test.stopTest();
Assert.areNotEqual(1, opps.size(), 'Expected test to find a single Opp');
}
Note: You can validate two instances of the same object. If they are same then this method not pass.
Assert.isNull()
Method Signature with two variations
public static void isNull(Object value)
public static void isNull(Object value, String msg)
Code Sample
@isTest
static void testIsNull() {
Test.startTest();
List<Opportunity> opps = [SELECT Id, AccountId FROM Opportunity];
opps = null;
Test.stopTest();
Assert.isNUll(opps);
Assert.isNUll(opps,'This is Null Value');
}
Note: You can validate if the value if null or not. There are two flavor of it. One with custom massage and other only with Validation. Recommendation is to use the method with custom message.
Assert.IsTrue()
Method Signature with two variations
public static void isTrue(Boolean condition)
public static void isTrue(Boolean condition, String msg)
Code Sample
@isTest
static void testIsTrue() {
List<Account> accts;
List<Contact> contacts;
TestFactory.generateAccountWithContacts(5);
Test.startTest();
accts = [SELECT Id FROM Account];
contacts = [SELECT Id FROM Contact];
Test.stopTest();
Assert.isTrue(contacts.size() == 6, 'Was expecting to find 6 contacts');
Assert.isTrue(contacts.size() == 6);
}
Note: Boolean value can be validated. There are two flavor of it. One with custom massage and other only with Validation. Recommendation is to use the method with custom message.
Assert.isNotInstanceOfType() & Assert.isInstanceOfType()
Method Signature
public static void isNotInstanceOfType(Object instance, System.Type notExpectedType)
public static void isNotInstanceOfType(Object instance, System.Type notExpectedType, String msg)
public static void isInstanceOfType(Object instance, System.Type expectedType)
Code Sample
@isTest
static void testIsNotInstanceOfType() {
Test.startTest();
List<Opportunity> opps = [SELECT Id, AccountId FROM Opportunity limit 1];
Account newAcct = new Account(Id=opps.get(0).AccountId);
Test.stopTest();
Assert.isNotInstanceOfType(newAcct,Account.class);
Assert.isInstanceOfType(newAcct, Account.class, 'Expected type.');
Assert.isNotInstanceOfType(newAcct, Contact.class, 'Contact and Account Not expected type');
}
Note: By using this method you can validate if two instances are from the same Object or not. In above example, I tried to compare two instances of Account and Contact with Assert.isNotInstanceOfType() and this passes however same condition would not pass for Assert.isInstanceOfType().There are two flavor of it. One with custom massage and other only with Validation. Recommendation is to use the method with custom message.
Assert.isFalse()
Method Signature with two Variations
public static void isFalse(Boolean condition)
public static void isFalse(Boolean condition, String msg)
Code Sample
@isTest
static void testIsFalse() {
Test.startTest();
List<Opportunity> opps = [SELECT Id, AccountId FROM Opportunity limit 1];
Boolean isSizeTwo = (opps.size() >1) ? true :false;
Test.stopTest();
Assert.isFalse(isSizeTwo);
}
Note: Boolean value can be validated but for false value only. There are two flavor of it. One with custom massage and other only with Validation. Recommendation is to use the method with custom message.
Assert.fail
Method signature with two variations
public static void fail(String msg)
public static void fail()
Code Sample
@isTest
static void testIsFail() {
Test.startTest();
List<Opportunity> opps = [SELECT Id, AccountId FROM Opportunity limit 1];
Integer size = opps.size();
Test.stopTest();
try {
Integer infinte = size/0;
Assert.fail('This is a Infinite Number');
} catch (MathException ex) {
}
}
Note: This can be used inside the Try/catch block however that assertion failure can not be caught in case exception is thrown. There are two flavor of it. One with custom massage and other only with Validation. Recommendation is to use the method with custom message.
Conclusion
All these different Assert methods are essentials for the test case coverage and should be used going forward instead of System.Assert(). On the other hand we need to find a way to transition our old test classes from System.Assert to Assert namespace. That’s a another topic of discussion and I will lay migration strategy for that in future.
Complete Class
@isTest
private class AssertTesting {
@testSetup
static void dataCreation() {
Account account = TestFactory.getAccount('Muddy Waters Inc.', true);
Contact contact = TestFactory.getContact(account.Id, 'Muddy', 'Waters', true);
Opportunity opp = New Opportunity();
opp.Name = 'Long lost record';
opp.AccountId = account.Id;
opp.CloseDate = Date.today().addDays(14);
opp.StageName = 'Prospecting';
insert opp;
}
@isTest
static void testAreNotEqual() {
Test.startTest();
List<Opportunity> opps = [SELECT Id, AccountId FROM Opportunity];
Test.stopTest();
Assert.areNotEqual(1, opps.size(), 'Expected test to find a single Opp');
}
@isTest
static void testIsNull() {
Test.startTest();
List<Opportunity> opps = [SELECT Id, AccountId FROM Opportunity];
opps = null;
Test.stopTest();
Assert.isNUll(opps);
Assert.isNUll(opps,'This is Null Value');
}
@isTest
static void testIsTrue() {
List<Account> accts;
List<Contact> contacts;
TestFactory.generateAccountWithContacts(5);
Test.startTest();
accts = [SELECT Id FROM Account];
contacts = [SELECT Id FROM Contact];
Test.stopTest();
Assert.isTrue(contacts.size() == 6, 'Was expecting to find 6 contacts');
Assert.isTrue(contacts.size() == 6);
}
@isTest
static void testIsNotInstanceOfType() {
Test.startTest();
List<Opportunity> opps = [SELECT Id, AccountId FROM Opportunity limit 1];
Account newAcct = new Account(Id=opps.get(0).AccountId);
Test.stopTest();
Assert.isNotInstanceOfType(newAcct,Account.class);
Assert.isInstanceOfType(newAcct, Account.class, 'Expected type.');
Assert.isNotInstanceOfType(newAcct, Contact.class, 'Contact and Account Not expected type');
}
@isTest
static void testIsFalse() {
Test.startTest();
List<Opportunity> opps = [SELECT Id, AccountId FROM Opportunity limit 1];
Boolean isSizeTwo = (opps.size() >1) ? true :false;
Test.stopTest();
Assert.isFalse(isSizeTwo);
}
@isTest
static void testIsFail() {
Test.startTest();
List<Opportunity> opps = [SELECT Id, AccountId FROM Opportunity limit 1];
Integer size = opps.size();
try {
Integer infinte = size/0;
Assert.fail('This is a Infinite Number');
} catch (MathException ex) {
}
Test.stopTest();
}
@isTest
static void testIsNotNull() {
List<Account> accts;
List<Contact> contacts;
TestFactory.generateAccountWithContacts(5);
Test.startTest();
accts = [SELECT Id FROM Account];
contacts = [SELECT Id FROM Contact];
Test.stopTest();
Assert.isNotNull(accts.size() > 0, 'Was expecting to find at least one account created');
}
}
Factory Class (Taken from Trailhead)
@isTest
public class TestFactory {
public static Account getAccount(String accountName, Boolean doInsert) {
Account account = new Account(Name = accountName);
if (doInsert) {
insert account;
}
return account;
}
public static Contact getContact(Id accountId, String firstName, String lastName, Boolean doInsert){
Contact contact = new Contact(
FirstName = firstName,
LastName = lastName,
AccountId = accountId
);
if (doInsert) {
insert contact;
}
return contact;
}
public static void generateAccountWithContacts(Integer numContacts) {
Account account = getAccount('default account ltd', true);
List<Contact> contacts = new List<Contact>();
for (Integer i = 0; i < numContacts; i++) {
String firstName = 'Contact';
String lastName = 'Test' + i;
contacts.add(getContact(account.Id, firstName, lastName, false));
}
insert contacts;
}
public static Opportunity[] generateOppsForAccount(ID accountId, Decimal amount, Integer numOpps){
List<Opportunity> oppsForAccounts = new List<Opportunity>();
for (Integer i = 0; i < numOpps; i++) {
Opportunity opp = new Opportunity(
Name = 'Account ' + i,
AccountId = accountId,
Amount = amount,
CloseDate = Date.today().addDays(5),
StageName = 'Prospecting'
);
oppsForAccounts.add(opp);
}
return oppsForAccounts;
}
public static User generateUser(String profileName) {
UserRole userRole = new UserRole(
DeveloperName = 'TestingTeam',
Name = 'Testing Team'
);
insert userRole;
String uniqueEmail = 'Cpt.Awesome' + DateTime.now().getTime() + '@th.example.com';
User userForInsert = new User(
ProfileId = [SELECT Id FROM Profile WHERE Name = :profileName].Id,
LastName = 'lastName',
Email = uniqueEmail,
Username = uniqueEmail,
CompanyName = 'Testing Co',
Title = 'Captain',
Alias = 'alias',
TimeZoneSidKey = 'America/Los_Angeles',
EmailEncodingKey = 'UTF-8',
LanguageLocaleKey = 'en_US',
LocaleSidKey = 'en_US',
UserRoleId = userRole.Id
);
insert userForInsert;
return userForInsert;
}
}
Disclaimer : This article is not endorsed by Salesforce or any other company in any way. This is my view and knowledge on the topic which I wrote. Please always refer to Official Documentation for the latest information.

Leave a Reply