You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Apex测试类未覆盖Item Type去重for循环,求解决方法

问题:Apex去重循环无法被测试类覆盖的优化方案

我开发了一个从POS_Item__c对象获取Item Type详情的Apex类,其中getItemTypeList_Apex方法包含提取唯一Item Type的for循环逻辑。现有测试类已创建测试数据,但始终无法覆盖该去重for循环。拒绝虚假覆盖,求正确的测试类优化方案。


业务类代码

public class ItemTypeWrapper {
    @AuraEnabled
    public Id ItemTypeId ;
    @AuraEnabled
    public String ItemType;
    public ItemTypeWrapper(Id ItemTypeId, String ItemType) {
        this.ItemTypeId = ItemTypeId;
        this.ItemType = ItemType;
    }
} 

//method to fetch details of the Item type from the sObject POS_Item__c
@AuraEnabled(cacheable=true)
public static List<ItemTypeWrapper> getItemTypeList_Apex()
{
    //variable to hold the account details
    objAccount=getAccount();
    //to fetch the profile details of the logged in user
    String profileName=[Select Id,Name from Profile where Id=:userinfo.getProfileId()].Name;
    //instance is created itemTypeResults of type List<POS_Item__c >
    List<POS_Item__c> itemTypeResults = new List<POS_Item__c>();
    //to hold the unique Item type ids 
    Set<Id> uniqueItemTypeIds = new Set<Id>();
    //check if the profileName is salesmanager
    if(profileName == folioSalesManagerProfile)
    {
       //fetch the item type details for salesmanager profile where marketing only is false
       itemTypeResults = [SELECT Id, Type_of_Item__r.Item_Type__c,Type_of_Item__c FROM POS_Item__c WHERE 
                                   Account__c=:objAccount.Id AND Active__c=true AND Item_ID__c!=null AND (Inventory_Seasonal_Program__c='Inventory' OR Inventory_Seasonal_Program__c='Both') AND Marketing_Only__c=false
                                   AND Logical_Invenory_Stock__c > 0 ORDER BY Type_of_Item__r.Item_Type__c];
    }
    else
    {
        itemTypeResults = [SELECT Id, Type_of_Item__r.Item_Type__c,Type_of_Item__c FROM POS_Item__c WHERE 
                                   Account__c=:objAccount.Id AND Active__c=true AND Item_ID__c!=null AND (Inventory_Seasonal_Program__c='Inventory' OR Inventory_Seasonal_Program__c='Both')
                                   AND Logical_Invenory_Stock__c > 0 ORDER BY Type_of_Item__r.Item_Type__c];
    }
    //instance is created itemTypeWrappers of type List<ItemTypeWrapper>
    List<ItemTypeWrapper> itemTypeWrappers = new List<ItemTypeWrapper>();
    //loop through the itemTypeResultsForAFacility , for each
    for (POS_Item__c result : itemTypeResults ) {
        //get the Item type record id and store it in a container itemTypeId
        Id itemTypeId = (Id)result.get('Type_of_Item__c');
        // Check if itemTypeId does not contains in the container uniqueItemTypeIds , if yes
        if (!uniqueItemTypeIds.contains(itemTypeId)) {
            //add the ItemType to the container ItemType
            String ItemType = result.Type_of_Item__r.Item_Type__c;
            //Create a new ItemTypeWrapper instance and add it to the list.
            itemTypeWrappers.add(new ItemTypeWrapper(itemTypeId, ItemType));
            //Add 'itemTypeId' to 'uniqueItemTypeIds' 
            uniqueItemTypeIds.add(itemTypeId);
        }
    }

    //return the itemTypeWrappers
    System.debug('itemTypeWrappers----'+itemTypeWrappers);
    return itemTypeWrappers;
}    

现有测试类代码

@isTest
public class testClass {
    @isTest
    private static void addToCartFunctionalityTestMethod ()
    {
        Account testAccount=[SELECT Id FROM Account LIMIT 1];
        Brand__c testBrand=[SELECT Id FROM Brand__c LIMIT 1];
        Item_Type__c testItemtype=[SELECT Id FROM Item_Type__c LIMIT 1];
        List<POS_Item__c> testPosItems=[SELECT Id FROM POS_Item__c];
        
        Test.startTest();
        ApexClass.getBrandList_Apex();
        ApexClass.getItemTypeList_Apex();
        Test.stopTest();
    }
    @testSetup static void setupData() {
        List<Account> testAccts = new List<Account>();
        Account acct = new Account(Name='demo');
        insert acct ;
        Contact contact=new Contact(LastName='Testing',AccountId=acct.Id);
        insert contact;
        Profile profile=[SELECT Name FROM Profile WHERE Name='Customer Community Plus User' LIMIT 1];
        
        User communityUser = new User(Alias = 'standt', Email='standarduser@testorg.com', 
                                      EmailEncodingKey='UTF-8', LastName='Testing', LanguageLocaleKey='en_US', 
                                      LocaleSidKey='en_US', ProfileId = profile.Id, 
                                      TimeZoneSidKey='America/Los_Angeles', UserName='standarduser@testorg.com',ContactId=contact.Id);
        
        insert communityUser;
        
        Brand__c brand = new Brand__c (Brand_Name__c='BrandNameSelect',Active__c=true,Account__c=acct.Id);
        insert brand;
        
        Item_Type__c itemType= new Item_Type__c(Item_Type__c='itemTypeSelect',Active__c=true,Account__c=acct.Id);
        insert itemType;
        POS_Item__c posItem= new POS_Item__c (Item_No__c='Test-No-01',Item_Name__c='testPosItemName',Available_Stock__c=10,
                                              Account__c=acct.Id,Brand__c=brand.Id,Type_of_Item__c=itemType.Id,Active__c=true);
        insert posItem;
        
        POS_Item__c posItem2= new POS_Item__c (Item_No__c='Test-No-02',Item_Name__c='testPosItemName',Available_Stock__c=10,
                                               Account__c=acct.Id,Brand__c=brand.Id,Type_of_Item__c=itemType.Id,Active__c=true);
        insert posItem2;
    }
}

问题根因

  1. 查询条件未满足:业务方法的SOQL包含Item_ID__c!=null、Inventory_Seasonal_Program__c枚举限制、Logical_Invenory_Stock__c > 0等过滤条件,但测试数据未设置这些字段,导致查询返回空列表,循环根本未执行。
  2. 用户上下文未切换:测试类创建了社区用户,但未用System.runAs切换到该用户执行测试,导致getAccount()获取的账户或Profile判断逻辑与预期不符。
  3. 去重逻辑未完全触发:现有测试数据仅创建了同一种Item Type的POS_Item,只能测试第一次进入判断分支的情况,无法覆盖重复Item Type时跳过的逻辑。

测试类优化方案

1. 补全测试数据的过滤字段

在setupData中给POS_Item__c补充业务方法要求的所有字段,同时创建多组不同Item Type的数据以触发去重逻辑:

@testSetup static void setupData() {
    // ... 原有账户、联系人、用户、品牌创建代码 ...
    
    Item_Type__c itemType= new Item_Type__c(Item_Type__c='itemTypeSelect',Active__c=true,Account__c=acct.Id);
    insert itemType;
    // 创建第一个Item Type的POS_Item,补全所有过滤字段
    POS_Item__c posItem= new POS_Item__c (
        Item_No__c='Test-No-01',
        Item_Name__c='testPosItemName',
        Available_Stock__c=10,
        Account__c=acct.Id,
        Brand__c=brand.Id,
        Type_of_Item__c=itemType.Id,
        Active__c=true,
        Item_ID__c='TEST-ID-001', // 满足Item_ID__c!=null
        Inventory_Seasonal_Program__c='Inventory', // 满足枚举条件
        Logical_Invenory_Stock__c=5, // 满足>0条件
        Marketing_Only__c=false
    );
    insert posItem;

    // 创建第二个不同的Item Type
    Item_Type__c itemType2= new Item_Type__c(Item_Type__c='itemTypeSelect2',Active__c=true,Account__c=acct.Id);
    insert itemType2;
    POS_Item__c posItem3= new POS_Item__c (
        Item_No__c='Test-No-03',
        Item_Name__c='testPosItemName3',
        Available_Stock__c=10,
        Account__c=acct.Id,
        Brand__c=brand.Id,
        Type_of_Item__c=itemType2.Id,
        Active__c=true,
        Item_ID__c='TEST-ID-003',
        Inventory_Seasonal_Program__c='Both',
        Logical_Invenory_Stock__c=3
    );
    insert posItem3;

    // 创建同第一个Item Type的POS_Item,测试去重跳过逻辑
    POS_Item__c posItem4= new POS_Item__c (
        Item_No__c='Test-No-04',
        Item_Name__c='testPosItemName4',
        Available_Stock__c=10,
        Account__c=acct.Id,
        Brand__c=brand.Id,
        Type_of_Item__c=itemType.Id,
        Active__c=true,
        Item_ID__c='TEST-ID-004',
        Inventory_Seasonal_Program__c='Inventory',
        Logical_Invenory_Stock__c=2
    );
    insert posItem4;
}

2. 切换到测试用户上下文执行

在测试方法中用System.runAs切换到创建的社区用户,确保上下文匹配:

@isTest
private static void getItemTypeList_Test() {
    User testUser = [SELECT Id FROM User WHERE UserName='standarduser@testorg.com'];
    
    Test.startTest();
    System.runAs(testUser){
        List<ItemTypeWrapper> result = ApexClass.getItemTypeList_Apex();
        // 断言去重结果:应返回2个唯一Item Type
        System.assertEquals(2, result.size(), '去重后需返回2个唯一的Item Type');
    }
    Test.stopTest();
}

3. 覆盖Sales Manager分支(可选)

若需覆盖folioSalesManagerProfile分支,需创建对应权限的测试用户并单独测试:

@testSetup static void setupData() {
    // ... 原有代码 ...
    
    // 创建Sales Manager用户
    Profile salesManagerProfile = [SELECT Id FROM Profile WHERE Name='Sales Manager' LIMIT 1];
    User salesManagerUser = new User(
        Alias = 'salesmgr', 
        Email='salesmgr@testorg.com', 
        EmailEncodingKey='UTF-8', 
        LastName='SalesMgr', 
        LanguageLocaleKey='en_US', 
        LocaleSidKey='en_US', 
        ProfileId = salesManagerProfile.Id, 
        TimeZoneSidKey='America/Los_Angeles', 
        UserName='salesmgr@testorg.com',
        ContactId=contact.Id
    );
    insert salesManagerUser;

    // 创建Marketing_Only__c=true的POS_Item,测试过滤逻辑
    POS_Item__c posItemMarketingOnly= new POS_Item__c (
        Item_No__c='Test-No-05',
        Item_Name__c='testMarketingItem',
        Available_Stock__c=10,
        Account__c=acct.Id,
        Brand__c=brand.Id,
        Type_of_Item__c=itemType.Id,
        Active__c=true,
        Item_ID__c='TEST-ID-005',
        Inventory_Seasonal_Program__c='Inventory',
        Logical_Invenory_Stock__c=4,
        Marketing_Only__c=true
    );
    insert posItemMarketingOnly;
}

@isTest
private static void getItemTypeList_SalesManager_Test() {
    User salesManagerUser = [SELECT Id FROM User WHERE UserName='salesmgr@testorg.com'];
    
    Test.startTest();
    System.runAs(salesManagerUser){
        List<ItemTypeWrapper> result = ApexClass.getItemTypeList_Apex();
        // 断言:MarketingOnly的Item会被过滤,仍返回2个唯一Item Type
        System.assertEquals(2, result.size(), 'Sales Manager需过滤Marketing Only类型的Item');
    }
    Test.stopTest();
}

内容的提问来源于stack exchange,提问作者Kavya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 19:14:51