Apex 테스트용 테스트 데이터 생성
학습 목표
이 유닛을 완료하면 다음을 수행할 수 있습니다.
- 테스트 유틸리티 클래스를 만들 수 있습니다.
- 테스트 유틸리티 메서드를 사용하여 다양한 테스트 케이스에 대한 테스트 데이터를 설정할 수 있습니다.
- 클래스의 모든 테스트 메서드를 실행할 수 있습니다.
Apex 테스트용 테스트 데이터 생성
테스트 유틸리티 클래스를 사용하여 테스트 데이터 설정에 재사용 가능한 메서드를 추가할 수 있습니다.
전제 조건
아직 수행하지 않은 경우 이전 유닛인 Apex 트리거 테스트의 전제 조건을 완료합니다.
테스트 유틸리티 클래스 추가
테스트 데이터 생성을 유틸리티 클래스 메서드에 대한 호출로 대체하여 이전 테스트 메서드를 리팩토링해 보겠습니다. 먼저 테스트 유틸리티 클래스를 만들어야 합니다.
TestDataFactory
클래스는 특별한 유형의 클래스이며, 이는 @isTest
라고 주석이 추가된 공개 클래스로 실행 중인 테스트에서만 액세스할 수 있습니다. 테스트 유틸리티 클래스에는 테스트 데이터 설정과 같은 유용한 작업을 수행하기 위해 테스트 메서드에서 호출할 수 있는 메서드가 포함되어 있습니다. 테스트 유틸리티 클래스는 조직의 코드 크기 제한에서 제외됩니다.
TestDataFactory
클래스에 추가하려면 다음 단계를 수행하세요.
- Developer Console에서 File(파일) | New(새로 만들기) | Apex Class(Apex 클래스)를 클릭하고 클래스 이름에 대해
TestDataFactory
를 입력한 다음 OK(확인)를 클릭합니다. - 기본 클래스 본문을 다음으로 바꿉니다.
@isTest public class TestDataFactory { public static List<Account> createAccountsWithOpps(Integer numAccts, Integer numOppsPerAcct) { List<Account> accts = new List<Account>(); for(Integer i=0;i<numAccts;i++) { Account a = new Account(Name='TestAccount' + i); accts.add(a); } insert accts; List<Opportunity> opps = new List<Opportunity>(); for(Integer j=0;j<numAccts;j++) { Account acct = accts[j]; // For each account just inserted, add opportunities for(Integer k=0;k<numOppsPerAcct;k++) { opps.add(new Opportunity(Name=acct.Name + ' Opportunity ' + k, StageName='Prospecting', CloseDate=System.today().addMonths(1), AccountId=acct.Id)); } } // Insert all opportunities for all accounts. insert opps; return accts; } }
이 테스트 유틸리티 클래스에는 하나의 정적 메서드 createAccountsWithOpps()
가 포함되어 있으며, 계정 개수(numAccts
매개변수) 및 각 계정에 대해 생성할 관련 기회 개수(numOppsPerAcct
매개변수)를 허용합니다. 메서드의 첫 번째 루프는 지정된 수의 계정을 생성하고 accts
목록 변수에서 이러한 계정을 저장합니다. 첫 번째 루프 후, insert()
DML 문은 데이터베이스의 목록에 있는 모든 계정을 생성하기 위해 호출됩니다.
두 번째 루프는 기회를 만듭니다. 각 기회 그룹이 하나의 계정에 연결되어 있으므로 외부 루프는 계정을 반복하고 현재 계정에 대한 관련 기회를 생성하는 중첩 루프를 포함합니다. 다음에 중첩 루프가 실행될 때 기회는 add()
메서드를 사용하여 동일한 목록에 추가됩니다. 기회는 AccountId
필드를 사용하여 상위 계정에 연결됩니다. 생성된 모든 기회의 총 수는 기회 개수와 계정 개수(numOppsPerAcct
*numAccts
의 제곱값입니다. 다음으로, insert()
DML 문은 루프 외부에서 효율적으로 호출되어 호출 한 번으로 모든 계정에 대한 컬렉션의 모든 기회를 생성합니다.
마지막으로 이 메서드는 새 계정 목록을 반환합니다.
테스트 데이터 생성을 위한 유틸리티 메서드 호출
이제 테스트 유틸리티 클래스를 추가했으므로 이 클래스를 활용하도록 TestAccountDeletion
테스트 클래스를 수정합니다. TestDataFactory.createAccountsWithOpps(1,1)
호출에 의해 반환된 배열에는 하나의 Account sObject가 포함됩니다.
다음은 수정된 테스트 메서드입니다. 더 짧은 버전입니다.
@isTest private class TestAccountDeletion { @isTest static void TestDeleteAccountWithOneOpportunity() { // Test data setup // Create one account with one opportunity by calling a utility method Account[] accts = TestDataFactory.createAccountsWithOpps(1,1); // Perform test Test.startTest(); Database.DeleteResult result = Database.delete(accts[0], false); Test.stopTest(); // Verify that the deletion should have been stopped by the trigger, // so check that we got back an error. System.assert(!result.isSuccess()); System.assert(result.getErrors().size() > 0); System.assertEquals('Cannot delete account with related opportunities.', result.getErrors()[0].getMessage()); } }
다양한 조건에 대한 테스트
하나의 테스트 메서드로는 트리거에 대해 가능한 모든 입력을 테스트하기에 충분하지 않습니다. 기회가 없는 계정이 삭제되는 경우와 같은 몇 가지 다른 조건을 테스트해야 합니다. 또한 단일 레코드 대신 대량 레코드를 사용하여 동일한 시나리오를 테스트해야 합니다. 다음은 세 가지 추가 테스트 메서드가 포함된 테스트 클래스의 업데이트된 버전입니다. 이 업데이트된 버전의 클래스를 저장합니다.
@isTest private class TestAccountDeletion { @isTest static void TestDeleteAccountWithOneOpportunity() { // Test data setup // Create one account with one opportunity by calling a utility method Account[] accts = TestDataFactory.createAccountsWithOpps(1,1); // Perform test Test.startTest(); Database.DeleteResult result = Database.delete(accts[0], false); Test.stopTest(); // Verify that the deletion should have been stopped by the trigger, // so check that we got back an error. System.assert(!result.isSuccess()); System.assert(result.getErrors().size() > 0); System.assertEquals('Cannot delete account with related opportunities.', result.getErrors()[0].getMessage()); } @isTest static void TestDeleteAccountWithNoOpportunities() { // Test data setup // Create one account with no opportunities by calling a utility method Account[] accts = TestDataFactory.createAccountsWithOpps(1,0); // Perform test Test.startTest(); Database.DeleteResult result = Database.delete(accts[0], false); Test.stopTest(); // Verify that the deletion was successful System.assert(result.isSuccess()); } @isTest static void TestDeleteBulkAccountsWithOneOpportunity() { // Test data setup // Create accounts with one opportunity each by calling a utility method Account[] accts = TestDataFactory.createAccountsWithOpps(200,1); // Perform test Test.startTest(); Database.DeleteResult[] results = Database.delete(accts, false); Test.stopTest(); // Verify for each record. // In this case the deletion should have been stopped by the trigger, // so check that we got back an error. for(Database.DeleteResult dr : results) { System.assert(!dr.isSuccess()); System.assert(dr.getErrors().size() > 0); System.assertEquals('Cannot delete account with related opportunities.', dr.getErrors()[0].getMessage()); } } @isTest static void TestDeleteBulkAccountsWithNoOpportunities() { // Test data setup // Create accounts with no opportunities by calling a utility method Account[] accts = TestDataFactory.createAccountsWithOpps(200,0); // Perform test Test.startTest(); Database.DeleteResult[] results = Database.delete(accts, false); Test.stopTest(); // For each record, verify that the deletion was successful for(Database.DeleteResult dr : results) { System.assert(dr.isSuccess()); } } }
모든 테스트 메서드 실행
마지막 단계는 테스트 클래스에서 테스트 메서드를 실행하며, 이제 클래스에 더 포괄적인 테스트가 포함되고 테스트 데이터 팩토리를 사용하도록 리팩토링되었습니다. TestAccountDeletion
클래스에서 이미 테스트를 실행했으므로 이 테스트 클래스를 다시 실행하여 모든 테스트 메서드를 실행할 수 있습니다.
- 동일한 테스트 실행을 실행하려면 Tests(테스트) 탭을 클릭하고 테스트 실행을 선택한 다음 Test(테스트) | Rerun(재실행)을 클릭합니다.
- 최신 테스트 실행을 확장하여 Tests(테스트) 탭에서 결과를 확인합니다. 테스트 실행은 네 가지 테스트가 모두 통과되었음을 보고해야 합니다.
리소스