進行状況の追跡を始めよう
Trailhead のホーム
Trailhead のホーム

Generate Data for Tests

Learning Objectives

After completing this unit, you’ll be able to:

  • Describe why creating data for tests is the best practice.
  • Create data specifically for unit tests.

Why Create Test Data?

A lot of developers are passionate about test data, and for good reason. Creating test data is one of the most important aspects of writing useful unit tests. Watch this video to learn more about why we create test data as part of our unit tests.


Two crucial aspects of a useful test are that it is descriptive and that every run results in the same outcome. A test that you run multiple times should always either fail or pass, unless you’ve changed the underlying code. Likewise, it should always be clear why a test failed. 

For these reasons, it’s tempting to use existing data from your production org, such as accounts or contacts, to run your tests. But that’s not a great idea. The Lightning Platform prevents developers from editing Apex classes in production orgs, so to write or edit tests, you have to use a development environment. That is, you have to use either a sandbox snapshot of your production org or a Developer Edition org. 

Naturally, the data in your production org changes over time and will be different from the data in your developer environment. When your tests run, either in a developer environment or in production, they have access only to the data in that org. So if you write tests using existing data, you can end up with deployment problems, because the data available in one environment isn’t always available in another environment.

That’s why it’s important for every test to create its own records. There are several methods for creating test data. In this unit we go through four of them.

Brute Force

You can create and insert the necessary records.

  1. Click Setup icon  and select Developer Console.
  2. Select File > New > Apex Class.
  3. Name the class DataGeneration_Tests.
  4. Replace the contents of the class with the following code.
    @isTest
      private class DataGeneration_Tests {
        @isTest static void testBruteForceAccountCreation() {
          List<Account> accts = new List<Account>();
          Test.startTest();
          accts = [SELECT Id FROM Account];
          Test.stopTest();
          System.assert(accts.size() > 0, 'Was expecting to find at least one account');
        }
      }
  5. Click File > Save, then Test > New Run.
  6. Select DataGeneration_Tests, then select testBruteForceAccountCreation.
  7. Select testBruteForceAccountCreation
  8. Click Run.

You can view the results of your test run by clicking on the Tests tab on the middle bar of the developer console. Because this test creates no accounts, this test run fails. To fix that, let's look at what the test is doing. 

This test is calling Test.startTest() and Test.stopTest(). These methods isolate the code you’re testing—in this case, the query for accounts—from your test setup. Any code between those two calls executes with a refreshed set of governor limits. If you want your test to pass, you need to create some accounts.

  1. Go back to your test class in the Developer Console.
  2. Insert a new line before Test.startTest(), and on this line, place the following code.
  3. Account a = new Account(name='McTesterson LLC');
    insert a;
  4. Save your class and repeat steps 5 through 7.

This time, the test should pass. 

This is effectively brute-forcing the solution. Before you call the underlying code that you’re testing, you’re creating the necessary data by creating and inserting objects. Brute force can work well, but it can lead to lengthy tests that are hard to follow. That is especially true when you start generating records that are related to other records and contain lots of field details. 

Test Factories

To make your tests simpler and easier to follow, you can move your data creation into a reusable class. Called data factories, these reusable classes contain methods that model the creation of one or more objects. You don’t even have to create your own test factory! A number of open-source data factories are available online. 

Let’s see what a basic test factory would look like, and how to use it.

  1. Click Setup icon  and select Developer Console.
  2. Select File > New > Apex Class.
  3. Name the class TestFactory.
  4. Replace the contents of the TestFactory class with the following code.
    @isTest
    public class TestFactory {
      public static Account getAccount(String name, Boolean doInsert){
        Account a = new Account(name = name);
        if(doInsert){
          insert a;
        }
        return a;
      }
      public static Contact getContact(Id accountId, String fname, String lname, Boolean doInsert){
        Contact c = new Contact(firstName = fname, lastName = lname, accountId = accountId);
        if(doInsert){
          insert c;
        }
        return c;
      }
      public static void generateAccountWithContacts(Integer numContacts){
        Account a = getAccount('default account ltd', true);
        List<Contact> contacts = new List<Contact>();
        for(Integer i = 0; i < numContacts; i++){
          String contactName = 'contact' + i;
          contacts.add(getContact(a.id, contactName, contactName, false));
        }
        insert contacts;
      }
      public static Opportunity[] generateOppsForAccount(id accountId, Decimal amount, Integer numOpps){
        List<Opportunity> opps = new List<Opportunity>();
        for(Integer i = 0; i < numOpps; i++){
          Opportunity o = new Opportunity();
          o.name = 'Account ' + i;
          o.accountId = accountid;
          o.amount = amount;
          o.closeDate = Date.today().addDays(5);
          o.stageName = 'Prospecting';
          opps.add(o);
        }
        return opps;
      }
      public static User generateUser(String profileName){
        UserRole userRole = new UserRole(DeveloperName = 'TestingTeam', Name = 'Testing Team');
        insert userRole;
        User u = new User(
          ProfileId = [SELECT Id FROM Profile WHERE Name = :profileName].Id,
          LastName = 'last',
          Email = 'Cpt.Awesome@awesomesauce.com',
          Username = 'Cpt.Awesome@awesomesauce.com',
          CompanyName = 'Testing Co',
          Title = 'Captian',
          Alias = 'alias',
          TimeZoneSidKey = 'America/Los_Angeles',
          EmailEncodingKey = 'UTF-8',
          LanguageLocaleKey = 'en_US',
          LocaleSidKey = 'en_US',
          UserRoleId = userRole.Id
        );
        insert u;
        return u;
      }
    }
  5. Click File > Save.

Code Highlights

This test factory isn’t very sophisticated, but it conveys the idea. This test factory class is built from a group of methods that generate and optionally insert data for use in testing. Notice the first line: @isTest? That means you can use the class and its methods only in the context of unit tests. Additionally, classes annotated with @isTest don’t count against your organization limits on the amount of Apex you can use. 

Your class offers methods to create accounts, contacts, and, more important, an account with five contacts. That is where data factories can really start to shine—in creating networks of related objects with a single line of code. 

To use your test factory, modify your DataGeneration_Tests.

  1. Click Setup icon  and select Developer Console.
  2. Select File > Open.
  3. Select the class DataGeneration_Tests.
  4. Place the following  code snippet after your first test.
    @isTest static void testUseTestFactoryToCreateAccountsWithContacts() {
      List<Account> accts;
      List<Contact> contacts;
      TestFactory.generateAccountWithContacts(5);
      Test.startTest();
      accts = [SELECT Id FROM Account];
      contacts = [SELECT Id FROM Contact];
      Test.stopTest();
      System.assert(accts.size() > 0, 'Was expecting to find at least one account');
      System.assertEquals(5, contacts.size(), 'Was expecting to find 5 contacts');
    }
  5. Click File > Save, then Test > New Run.
  6. Select DataGeneration_Tests, then select testUseTestFactoryToCreateAccountsWithContacts.
  7. Select testUseFactoryToCreateAccountsWithContacts
  8. Click Run.

Code Highlights

As in your first test, you’re checking to ensure that your test is creating test data. In this case, however, you’re using your test factory class to create the data. 

TestSetup Methods

When we create tests, we want to keep them as succinct and easy to follow as possible. Separating data creation into a test factory helps, but we can go one step further.

Multiple test methods in the same class often have similar data requirements. Because of this, the Lightning Platform offers a way for you to annotate methods in your test class as @testSetup methods. The platform calls these methods automatically before every individual test method. Because they’re called before every test method in the class, they’re perfect for creating test data. Note, however, that the data is reset in between each and every test method's execution. 

Let’s create a testSetup method.

  1. Go back to your DataGeneration_Tests class in the Developer Console.
  2. Add the following setup method at the top of the file, just under the line saying private.
    @TestSetup
    static void dataCreation(){
      Account a = TestFactory.getAccount('Muddy Waters Inc.', true);
      Contact c = TestFactory.getContact(a.id, 'Muddy', 'Waters', true);
      Opportunity opp = New Opportunity();
      opp.name = 'Long lost record';
      opp.accountId = a.id;
      opp.closeDate = Date.today().addDays(14);
      opp.stageName = 'prospecting';
      insert opp;
    }
  3. Click File > Save, then Test > New Run.
  4. Select DataGeneration_Tests, then select testUseTestFactoryToCreateAccountsWithContacts.  
    Select testUseTestFactoryToCreateAccountsWithContacts
  5. Click Run.

Uh-oh, adding this @testSetup method broke the second test method. Specifically, the assertion failed with the error message “Assertion Failed: Was expecting to find 5 contacts.” 

The test failed because your @testSetup method creates a contact before the platform runs the test method. That contact, combined with the 5 contacts your test method creates, means that your test’s query finds 6, not 5, contacts. These additional records demonstrate the platform’s execution of @testSetup methods prior to actually executing test methods. They also demonstrate the ability of the @testSetup method to create records for testing. 

To fix your failing test, modify the assertions to say 6, rather than 5.

  1. Go back to your DataGeneration_Tests class in the Developer Console.
  2. Find the line of code that reads:
    System.assert(contacts.size() == 5, 'Was expecting to find 5 contacts');
  3. Modify that line of code to specify 6 contacts, like this:
    System.assert(contacts.size() == 6, 'Was expecting to find 6 contacts');
  4. Click File > Save, then Test > New Run.
  5. Select DataGeneration_Tests, then select testUseTestFactoryToCreateAccountsWithContacts.

Code Highlights

This testSetup method is pretty basic, but it does incorporate some of what you’ve already done; namely, use your test factory to generate data. 

Lets add a new testMethod to look for opportunities.

  1. Go back to your DataGeneration_Tests class in the Developer Console.
  2. Create a new test method with the following code:
    @isTest static void testAtTestSetupMethodsRule(){
      List<Opportunity> opps = [SELECT Id, AccountId FROM Opportunity];
      System.assertEquals(1, opps.size(), 'Expected test to find a single Opp');
    }
  3. Click File > Save, then Test > New Run.
  4. Select DataGeneration_Tests, then select testAtTestSetupMethodsRule.
  5. Select testAtTestSetupMethodsRule
  6. Click Run.

Code Highlights

Notice this third test method passes, even though it’s not creating data. In this test method, you’re relying on the platform to pre-execute the @testSetup method, which creates the opportunity you need for the test to pass. Note, even though the @testSetup method creates the test data, you still have to query for that data within your test. This can be confusing when you first start using @testSetup methods.

CSV Data Files

Using the testSetup methods allows for concise, focused tests, but we can go yet another step further with our test data. We can create and upload a CSV file as a static resource and generate test data directly from that CSV. 

Imagine a scenario where you can expand the scope of your tests without changing a line of code. CSV data lets you add to or modify the data inputs your code deals with, without deploying code. 

  1. Using a text editor(like Text edit, Visual Studio Code, or Sublime Text), paste the following into a file and save it as accountData.csv.

    Name,Website,Phone,BillingStreet,BillingCity,BillingState,BillingPostalCode,BillingCountry
    sForceTest1,http://www.sforcetest1.com,(415) 901-7000,The Landmark @ One Market,San Francisco,CA,94105,US
    sForceTest2,http://www.sforcetest2.com,(415) 901-7000,The Landmark @ One Market Suite 300,San Francisco,CA,94105,US
    sForceTest3,http://www.sforcetest3.com,(415) 901-7000,1 Market St,San Francisco,CA,94105,US
  2. In Setup, type Static Resources in the Quick Find box and select Static Resources.
  3. Click New.
  4. Name your static resource accountData and set the cache control to public.
  5. Click Choose File and select accountData.csv.
  6. Click Save.

Now create a new test class in the Developer Console.

  1. Select File > New > Apex Class.
  2. Name the class CSV_Tests and replace its contents with the following code.
    @isTest
    private class CSV_Tests {
      @TestSetup
      static void loadTestDataFromStaticResource(){
        List<sObject> accounts = Test.loadData(Account.SObjectType, 'accountData');
      }
      @isTest static void testLoadAccountsFromStaticResource() {
        List<Account> accts = [SELECT ID FROM Account];
        system.assert(accts.size() == 3, 'expected 3 accounts');
      }
    }
  3. Click File > Save, then Test > New Run.
  4. Select CSV_Tests, then select testLoadAccountsFromStaticResource.
  5. Select testLoadAccountsFromStaticResource
  6. Click Run.

Code Highlights

This code still uses an @TestSetup method. But instead of using a testFactory or brute forcing it, you’re simply loading the CSV file. This makes for super-clean tests and lets you add to or modify your test data without deploying code.

Resources