Skip to content

Class Name: TestDataFactory

Last Updated: 2025-10-22 Source Code: https://github.com/AANP-IT/I2C.Salesforce.Metadata/blob/STAGING/force-app/main/default/classes/TestDataFactory.cls

API Name: TestDataFactory Type: Test Utility Test Coverage: N/A (Test utility class)

Business Purpose

The TestDataFactory class provides centralized test data generation utilities for Apex test classes. This ensures: - Consistent test data across all test classes - Reduced code duplication in tests - Easy maintenance of test record structures - Support for Commerce Cloud and custom object testing - Valid record creation with required fields populated

This is a foundational test utility class used throughout the test suite.

Class Overview

  • Author: Ecaterina Popa
  • Created: 07/21/2024
  • Last Modified: 09/03/2024
  • Scope: @IsTest - Only available in test context
  • Key Responsibilities:
  • Create Account records (Business and Person Accounts)
  • Create Commerce Cloud objects (WebStore, WebCart, CartItem, Order, OrderSummary)
  • Create Product2, Pricebook2, and PricebookEntry records
  • Create custom objects (Membership__c, Subscription__c, PracticeSite__c, AANP_Event__c)
  • Create User records for portal testing
  • Support both insert and return patterns

Constants

private static final String COUNTRY = 'United States';
private static final String COUNTRY_CODE = 'US';
private static final String STATE = 'Alabama';
private static final String STATE_CODE = 'AL';
private static final String CITY = 'Fairfield';
private static final String ADDRESS = '5500 Myron Massey Blvd';
private static final String ZIP = '35064';
private static final String PREF_MAIL_ADDR = 'Home';

Purpose: Default address values for test records.

Public Methods

Account Methods

getAccountRecord (Simple)

public static Account getAccountRecord(Boolean doInsert)

Creates: Business Account with default values including Fellow fields.

Key Fields: - RecordType: 'Business_Account' - Phone: '+11234567890' Phone_Type__c: 'Mobile' - Fellow fields: Is_a_Fellow__c = true, Fellow_Designation__c = 'Employee' - Complete billing and shipping addresses

getAccountRecord (Parameterized)

public static Account getAccountRecord(String name, String phone, String city, String address, String zip, Boolean doInsert)

Creates: Business Account with custom values.

convertAccountToPersonAccount

public static Account convertAccountToPersonAccount(String accId, String conId)

Purpose: Converts Business Account to Person Account.

Issues/Concerns: - ⚠️ Unused Parameter: conId parameter not used in implementation (line 103) - ⚠️ Direct Conversion: Doesn't create PersonContact relationship - ✅ RecordType Switch: Changes RecordType to 'PersonAccount'

Contact Methods

getContactRecord

public static Contact getContactRecord(String accId, Boolean doInsert)

Creates: Contact with unique email and mailing address.

Key Feature: Uses System.now().millisecond() for unique emails.

User Methods

getPortalUser

public static User getPortalUser(Boolean doInsert)

Purpose: Creates portal user for Experience Cloud testing.

Process: 1. Creates Business Account 2. Creates Contact 3. Converts to Person Account 4. Creates User with 'AANP External Identity User' profile

Issues/Concerns: - ⚠️ Complex Setup: Multiple DML operations (Account, Contact, Account update, User) - ⚠️ Profile Dependency: Hardcodes 'AANP External Identity User' profile - ✅ Unique Username: Uses timestamp for uniqueness

Utility Methods

getRandomNumber

public static String getRandomNumber(integer stringLength)

Purpose: Generates random numeric string with leading zeros.

Example: getRandomNumber(8) → "03847562"

Issues/Concerns: - ✅ Left Padding: Maintains consistent length with leading zeros - ✅ Unique Values: Uses Math.Random() for uniqueness

Commerce Cloud Methods

WebStore Objects

getWebStore: Creates WebStore (Type: 'B2C')

getWebCart: Creates WebCart with Active status

getCartDeliveryGroup: Creates CartDeliveryGroup with default address

getCartItems: Creates 2 CartItem records at $100 each

Product and Pricing

getProduct: Creates single Product2 with random SKU

getProductsList: Creates multiple Product2 records (family: 'Memberships')

getShippingProduct: Creates 'Shipping Charge' product

getStandardPricebook: Returns Test.getStandardPricebookId()

getWebStorePricebook: Creates custom pricebook with Type__c

getPricebookEntry: Creates PricebookEntry at $100

Order Objects

getOrder: Creates Commerce Order (RecordType: 'Commerce Order')

getDigitalOrderDeliveryMethod: Creates digital delivery method

getOrderDeliveryGroup: Creates OrderDeliveryGroup with default address

getOrderItem: Creates OrderItem and activates parent Order

getOrderSummary: Creates OrderSummary via ConnectApi

getFulFillOrder: Creates FulfillmentOrder via ConnectApi

getOrderPaymentSummary: Creates OrderPaymentSummary via ConnectApi

getPayment: Creates Payment (Status: 'Draft', Amount: $100)

Custom Object Methods

getMembership

public static Membership__c getMembership(Boolean doInsert, OrderItem orderItem, Account acct)

Creates: Membership__c linked to OrderItem with 1-year duration.

createSubscription

public static Subscription__c createSubscription(final String accountId, final String productId)

Creates: Active Subscription__c with 12-month duration and auto-renewal.

createPracticeSite

public static PracticeSite__c createPracticeSite(String accountId)

Creates: Complete PracticeSite__c with all optional fields populated.

Key Fields: Address, phones, website, age groups, clinical focus, payors, etc.

createAANPEvents

public static List<AANP_Event__c> createAANPEvents(Integer numEvents, Integer daysFromToday, Integer externalId, Boolean doInsert)

Creates: Multiple AANP_Event__c records with sequential dates.

Features: - Alternates between 'In-person' and 'Virtual' types - Sequential event IDs starting from externalId - Registration enabled by default

createAANPEventAttendees

public static List<AANP_Event_Attendee__c> createAANPEventAttendees(List<AANP_Event__c> events, Id personAccountId, Boolean doInsert, Integer startingEventAttendeeId, Integer accountExternalId)

Creates: Event attendee records for each event.

Buyer Account Methods

getBuyerAccount

public static BuyerAccount getBuyerAccount(Boolean doInsert, String accId)

Purpose: Queries or creates BuyerAccount.

Issues/Concerns: - 🚨 Query in Test Method: Queries BuyerAccount instead of always creating (line 518) - ⚠️ doInsert Logic: Only inserts if query returns empty AND doInsert=true - ⚠️ Return Empty Element: Returns buyerAccs[0] which could be empty list

Correct Implementation:

public static BuyerAccount getBuyerAccount(Boolean doInsert, String accId) {
    BuyerAccount ba = new BuyerAccount(
        BuyerId = accId,
        Name = 'Test Buyer',
        IsActive = true
    );
    if (doInsert) {
        insert ba;
    }
    return ba;
}

Promotion Methods

getPromotionTarget: Creates PromotionTarget (5% discount on product)

getPromotion: Creates Promotion (Name: 'SALE2024')

getCoupon: Creates Coupon linked to promotion

Design Patterns

  1. Factory Pattern: Static factory methods for creating test records
  2. Builder Pattern: Optional doInsert parameter for flexibility
  3. Consistent Naming: get* prefix for single records, get*List for collections
  4. Constants: Centralized default values
  5. Chaining: Methods can call other factory methods (e.g., getPortalUser)

Best Practices

✅ Good Practices

  1. doInsert Parameter: Allows creating records without DML for performance
  2. Unique Values: Uses timestamps and random numbers for uniqueness
  3. Complete Records: Populates all required fields
  4. Centralized Constants: Easy to update address values
  5. ConnectApi Usage: Proper OrderSummary and FulfillmentOrder creation

⚠️ Areas for Improvement

  1. getBuyerAccount Query (line 518): Shouldn't query in test factory
  2. Unused Parameter (line 103): conId not used in convertAccountToPersonAccount
  3. Hardcoded Profile (line 139): 'AANP External Identity User' may not exist in all orgs
  4. Complex getPortalUser: Multiple DML operations reduce test performance
  5. No Validation: Doesn't validate required parameters

Usage Examples

Simple Account Creation

@IsTest
static void testExample() {
    Account acc = TestDataFactory.getAccountRecord(true); // Inserted
    Assert.isNotNull(acc.Id, 'Account should be inserted');
}

Order with OrderSummary

@IsTest
static void testOrderFlow() {
    // Setup
    Pricebook2 pb = TestDataFactory.getStandardPricebook();
    Product2 prod = TestDataFactory.getProduct(true);
    PricebookEntry pbe = TestDataFactory.getPricebookEntry(true, prod, pb);
    Order order = TestDataFactory.getOrder(true, pb);
    OrderDeliveryMethod odm = TestDataFactory.getDigitalOrderDeliveryMethod(true);
    OrderDeliveryGroup odg = TestDataFactory.getOrderDeliveryGroup(true, odm, order);
    OrderItem item = TestDataFactory.getOrderItem(true, prod, odg, order, pbe);

    // Create OrderSummary
    String osId = TestDataFactory.getOrderSummary(order.Id);
    Assert.isNotNull(osId, 'OrderSummary should be created');
}

Bulk Products

@IsTest
static void testBulkProducts() {
    List<Product2> products = TestDataFactory.getProductsList(true, 100);
    Assert.areEqual(100, products.size(), 'Should create 100 products');
}

Dependencies

Salesforce Objects

  • Standard Objects: Account, Contact, User, Product2, Pricebook2, PricebookEntry, Order, OrderItem, OrderSummary, etc.
  • Custom Objects: Membership__c, Subscription__c, PracticeSite__c, AANP_Event__c, AANP_Event_Attendee__c

Profiles & RecordTypes

  • Profile: 'AANP External Identity User', 'System Administrator'
  • RecordType: 'Business_Account', 'PersonAccount', 'Commerce Order'

ConnectApi

  • ConnectApi.OrderSummaryCreation
  • ConnectApi.FulfillmentOrder
  • ConnectApi.OrderPaymentSummary

Pre-Go-Live Concerns

🚨 CRITICAL

  • getBuyerAccount Query (line 518): Queries in test method
  • Remove query logic, always create new record
  • Could cause test failures if buyer account exists

MEDIUM

  • Unused Parameter (line 103): conId parameter never used
  • Remove or implement functionality
  • Hardcoded Profile (line 139): May not exist in all orgs
  • Add null check or make profile name configurable

LOW

  • Complex getPortalUser: Multiple DML operations slow tests
  • Consider lighter version for performance

Changes & History

Date Author Description
07/21/2024 Ecaterina Popa Initial implementation
09/03/2024 Ecaterina Popa Last modification

Documentation Status: ✅ Complete Code Review Status: ⚠️ HIGH - Fix getBuyerAccount query logic Test Coverage: N/A (Test utility class) Usage: Used across all test classes in org