Right Way to Generate Unit Test Using AI
As developers, we’re constantly looking for ways to streamline our workflow. One of the most exciting recent developments has been using Generative AI to help us write unit tests. But is AI truly helping us write better tests, or just faster ones? Based on my hands-on experience, I want to share some insights about the right approach to AI-assisted testing.
The Trap of “Logic-Based” Testing
When we ask AI to generate tests based on our existing code, we fall into an interesting trap. The AI dutifully analyzes our implementation and creates tests that verify our code works as written — not necessarily as intended.
Let me explain with a simple Salesforce example. Imagine we have these requirements for account creation:
- Given a Standard user, when they create an Account named “Test,” then they should see an error message.
- Given an Admin user, when they create an Account named “Test,” then the account should be created successfully.
- Given a Data Integration user, when they create an Account named “Test,” then the account should be created successfully.
Now, suppose a developer implemented this validation logic in trigger Handler: If you notice developer missed one scenario.
public class AccountHandler {
public static void validateAccountName(List<Account> newAccounts) {
for (Account acc : newAccounts) {
if (UserInfo.ProfileName != 'System Administrator' && acc.Name.equalsIgnoreCase('Test')) {
acc.addError("You can't create Test accounts.");
}
}
}
}
If you ask Gen AI to write tests for this method, you’ll likely get something like:
@isTest
public class AccountTriggerHandlerTest {
@testSetup
static void setupTestData() {
// Create Standard User
Profile standardProfile = [SELECT Id FROM Profile WHERE Name = 'Standard User'];
User standardUser = new User(
FirstName = 'Standard',
LastName = 'User',
Email = 'standarduser@example.com',
Username = 'standarduser@example.com',
Alias = 'stdusr',
TimeZoneSidKey = 'America/Los_Angeles',
LocaleSidKey = 'en_US',
EmailEncodingKey = 'UTF-8',
ProfileId = standardProfile.Id,
LanguageLocaleKey = 'en_US'
);
insert standardUser;
// Create Admin User
Profile adminProfile = [SELECT Id FROM Profile WHERE Name = 'System Administrator'];
User adminUser = new User(
FirstName = 'Admin',
LastName = 'User',
Email = 'adminuser@example.com',
Username = 'adminuser@example.com',
Alias = 'admusr',
TimeZoneSidKey = 'America/Los_Angeles',
LocaleSidKey = 'en_US',
EmailEncodingKey = 'UTF-8',
ProfileId = adminProfile.Id,
LanguageLocaleKey = 'en_US'
);
insert adminUser;
}
@isTest
static void testStandardUserCannotCreateTestAccount() {
// Get Standard User
User standardUser = [SELECT Id FROM User WHERE Email = 'standarduser@example.com'];
// Run as Standard User
System.runAs(standardUser) {
Test.startTest();
Account acc = new Account(Name = 'Test');
try {
insert acc;
System.assert(false, 'Expected an exception but did not get one.');
} catch (DmlException e) {
System.assert(e.getMessage().contains('You are not authorized to create an Account named "Test".'),
'Standard User should not be able to create "Test" Account');
}
Test.stopTest();
}
}
@isTest
static void testAdminUserCanCreateTestAccount() {
// Get Admin User
User adminUser = [SELECT Id FROM User WHERE Email = 'adminuser@example.com'];
// Run as Admin User
System.runAs(adminUser) {
Test.startTest();
Account acc = new Account(Name = 'Test');
insert acc;
System.assertNotEquals(null, acc.Id, 'Admin should be able to create "Test" Account');
Test.stopTest();
}
}
}
Notice the problem? These tests verify what our code does, not what it should do. The implementation blocks all users exluding admin users from creating “Test” accounts, completely ignoring our requirements about Data Integration users.
A Better Approach: Requirements-First Testing
Instead of asking AI to test our implementation, we should ask it to test our requirements. Here’s how to craft a better prompt:
"You are Salesforce developer and you are tasked to write Apex Test for the Story with below Acceptance Criteria.
1. Give as a Standard user with Profile **Sales Ops** When I try to create Account with Name "Test" Then I should be see below error message.
2. Give as a **System Admin** When I try to create Account with Name "Test" Then I should be able to create account successfully.
3. Given a Data Integration User Custom Admin Profile with with Custom Permission "Skip Validation", when I try to create an Account named "Test," I should be able to create the account successfully
Please follow instructions strictly.
Instructions:
"""
1. Make sure to Follow Salesforce Best Practice.
2. Do you use any third party Lib unless specified.
3. Make sure use Assert Class to Assert Changes.
"""
With this approach, AI generates tests that verify our requirements — not just our current implementation. Here’s what the AI-generated code looks like when properly prompted:
@isTest
public class AccountCreationTest {
@testSetup
static void setupTestData() {
// Create Users with necessary profiles and permissions
Profile salesOpsProfile = [SELECT Id FROM Profile WHERE Name = 'Sales Ops' LIMIT 1];
Profile sysAdminProfile = [SELECT Id FROM Profile WHERE Name = 'System Administrator' LIMIT 1];
Profile dataIntegrationProfile = [SELECT Id FROM Profile WHERE Name = 'Custom Admin' LIMIT 1];
PermissionSet permSet = [SELECT Id FROM PermissionSet WHERE Name = 'Skip_Validation' LIMIT 1];
User salesOpsUser = new User(
FirstName = 'Sales', LastName = 'Ops',
Email = 'salesops@example.com',
Username = 'salesops@example.com',
Alias = 'salesop',
ProfileId = salesOpsProfile.Id,
TimeZoneSidKey = 'America/Los_Angeles',
LocaleSidKey = 'en_US',
EmailEncodingKey = 'UTF-8',
LanguageLocaleKey = 'en_US'
);
insert salesOpsUser;
User sysAdminUser = new User(
FirstName = 'System', LastName = 'Admin',
Email = 'sysadmin@example.com',
Username = 'sysadmin@example.com',
Alias = 'sysadm',
ProfileId = sysAdminProfile.Id,
TimeZoneSidKey = 'America/Los_Angeles',
LocaleSidKey = 'en_US',
EmailEncodingKey = 'UTF-8',
LanguageLocaleKey = 'en_US'
);
insert sysAdminUser;
User dataIntegrationUser = new User(
FirstName = 'Data', LastName = 'Integration',
Email = 'dataintegration@example.com',
Username = 'dataintegration@example.com',
Alias = 'datain',
ProfileId = dataIntegrationProfile.Id,
TimeZoneSidKey = 'America/Los_Angeles',
LocaleSidKey = 'en_US',
EmailEncodingKey = 'UTF-8',
LanguageLocaleKey = 'en_US'
);
insert dataIntegrationUser;
// Assign Custom Permission to Data Integration User
PermissionSetAssignment permAssignment = new PermissionSetAssignment(
AssigneeId = dataIntegrationUser.Id,
PermissionSetId = permSet.Id
);
insert permAssignment;
}
@isTest
static void testSalesOpsUserCannotCreateTestAccount() {
User salesOpsUser = [SELECT Id FROM User WHERE Username = 'salesops@example.com' LIMIT 1];
System.runAs(salesOpsUser) {
Test.startTest();
Account acc = new Account(Name = 'Test');
try {
insert acc;
Assert.fail('Expected validation exception was not thrown');
} catch (DmlException e) {
Assert.contains('You cannot create an Account with name Test', e.getMessage(), 'Error message did not match expectation');
}
Test.stopTest();
}
}
@isTest
static void testSystemAdminCanCreateTestAccount() {
User sysAdminUser = [SELECT Id FROM User WHERE Username = 'sysadmin@example.com' LIMIT 1];
System.runAs(sysAdminUser) {
Test.startTest();
Account acc = new Account(Name = 'Test');
insert acc;
Assert.isNotNull(acc.Id, 'Account was not created successfully');
Test.stopTest();
}
}
@isTest
static void testDataIntegrationUserCanCreateTestAccount() {
User dataIntegrationUser = [SELECT Id FROM User WHERE Username = 'dataintegration@example.com' LIMIT 1];
System.runAs(dataIntegrationUser) {
Test.startTest();
Account acc = new Account(Name = 'Test');
insert acc;
Assert.isNotNull(acc.Id, 'Account was not created successfully');
Test.stopTest();
}
}
}
Notice how different this is! The AI-generated tests now properly:
- Set up different user profiles with appropriate permissions
- Test each requirement separately

Why This Matters
Testing against requirements is crucial because:
- Catches bugs early — Tests fail if the code doesn’t meet requirements.
- Acts as living documentation — Clearly defines expected behavior.
- Ensures better coverage — Each scenario is properly validated.
Key Takeaways
From my experience working with Gen AI for testing, here are the most important lessons:
- Provide requirements to Prompts— Don’t just share code.
- Be specific — Include profiles, permissions, and details.
- Set clear standards — Give clear instructions to reduce hallucination and improve accuracy.
By approaching AI-assisted testing this way, we leverage AI’s strengths while avoiding its limitations. The AI becomes a partner in building better software, not just a tool for automating busy work.
What’s your experience with using AI for unit testing? Have you found other approaches that work well? I’d love to hear your thoughts in the comments!