3

According to this Salesforce guide and this forum answer, viewstat record will be created if we use UPDATE VIEWSTAT clause at the end of the query. However its not working as expected in my Test Class.

Below is the code I am working on.

Customer_Facing_Popup__kav newArticle2 = new Customer_Facing_Popup__kav(Title='test article2', UrlName='testarticleur2', Language='en_US',IsVisibleInPkb = True);  
insert newArticle2; 
List<Customer_Facing_Popup__kav> dummyList = [SELECT Title FROM Customer_Facing_Popup__kav WHERE Language = 'en_US' AND ID = :newArticle2.Id UPDATE VIEWSTAT]; //Should create ViewStat records. 
System.debug([SELECT parentId, viewCount, channel FROM Customer_facing_popup__viewstat]); //Returning zero records

Any pointers on how to create ViewStat records in test class?

  • Have you tried it with Test.stopTest? – Adrian Larson Dec 26 '17 at 6:52
  • Yes, I thought it might be asynchronous, but Test.stopTest is not helping. – Santanu Halder Dec 26 '17 at 7:13
3

This is probably covered as a known limitation of unit testing. As mentioned in Isolation of Test Data from Organization Data in Unit Tests:

There might be some cases where you can’t create certain types of data from your test method because of specific limitations ... Records that are created only after related records are committed to the database ...

I would speculate that since things like "tracked changes" and the like can't be created in unit tests, it would make sense that you also couldn't create/update a view stat in a unit test, either.

Some basic testing shows that view stats aren't even updated in real time. I tried several live tests and found that the view stats are updated at some later point after the actual view occurs.

I tried several tests, including publishing the article in a testSetup method beforehand and calling a update viewstat query in the testSetup method, and each result was the same: no view stat records were created.

As such, you'll need "mock" around this somehow, probably by querying the data into a static or class variable, and then manipulating it from the unit test. There is no way that I could find to get a "real" view stat for an article created during a unit test.

  • Thanks @sfdcfox for the detailed answer, I too have tested the same and found same results but could not find any documentation specifying about this. – Santanu Halder Dec 27 '17 at 6:14
2

As per @sfdcfox, you are going to need to mock these using a mocking technique

Here's an example using ApexMocks and Force.com Enterprise Architetcure Selector layer (my example is Accounts but you can adapt for your use case)

Selector class

public virtual class AccountsSelector implements IAccountsSelector {
    /**
        Force.com Enterprise Architecture Separation of Concerns Selector Layer: Accounts
        All selectors follow this pattern. Enables mocking through the Application.Selector.setMock

        Usage:
        Account[] accts = AccountsSelector.newInstance().selectXXXX(args)

        See Force.com Enterprise Architecture 2nd Edition Chapter 7
    **/

    public override String getOrderby() {return 'Name';}        // default field to order results by if not otherwise specified

    public List<Schema.SObjectField> getSObjectFieldList() {    // keep in alpha order
        return new List<Schema.SObjectField> {  
            Account.ID,
            Account.Name,
            Account.MyCustomField__c,  // as needed
            Account.RecordTypeId
        };
    }

    /**
    *   Factory to provide caller with a new Selector. Enables selectors to be mocked 
    **/ 
    public static IAccountsSelector newInstance()    {
        return (IAccountsSelector) Application.Selector.newInstance(Account.SObjectType);
    }

    /**
    *   getSObjectType : Used to construct queries. Required. 
    **/
    public Schema.SObjectType getSobjectType() {return Account.SObjectType;}

    /**
    *   selectById  : default selector, returns all matching SObjects for fields defined by getSObjectFieldList
    **/
    public virtual Account[] selectById(set<ID> ids) {
        return ids.isEmpty() ? new List<Account> () : (Account[]) selectSObjectsById(ids);
    }

    /**
    *  custom selector
    **/
    public virtual Account[] selectByName(set<String> names) {
       fflib_QueryFactory aQF = newQueryFactory()
                                .setCondition('Name IN :names);
       return Database.query(aQF.toSOQL());
    }
}

Use in code-under-test

...
Account[] accounts = AccountsSelector.newInstance()
                      .selectByName(someSetOfNames);
...

Test method

   fflib_ApexMocks mocks = new fflib_ApexMocks();
   // Given mock Accounts selector
   AccountsSelector mockAcctsSelector = (AccountsSelector) mocks.mock(AccountsSelector.class);
   // Given stubbing for selector; for ViewStat, you may need to use sfab_SObjectFabricator or equivalent Json trick
   Account[] mockAccounts = new list<Account> {
               new Account(Id = ..., Name = ..., ...),
               new Account(...)
        };
   mocks.startStubbing();
   mocks.when(mockAcctsSelector.SObjectType()).thenReturn(Account.SObjectType);
   mocks.when(mockAcctsSelector.selectByName((set<String>)fflib_Match.anyObject()))
                                                                .thenReturn(mockAccounts);
    mocks.stopStubbing();
    // Given mocks injested
    Application.Selector.setMock(mockAcctsSelector);

    // When relevant method under test
    Test.startTest();
    new MyClass().myMethod();
    Test.stopTest();

    // Then verify
    ... asserts or mocks.verify as appropriate
  • Thank you @cropredy, This looks promising, I will explore the Force.com Enterprise Architecture Selector layer. – Santanu Halder Dec 27 '17 at 6:15
  • @SantanuHalder I have some blog posts on apexmocks at cropredysfdc.com after you absorb the Selector Layet (also described in Trailhead). ApexMocks is an investment in time that pays off. If you know Mockito from Java (I didn’t) it will be familiar. – cropredy Dec 27 '17 at 14:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.