From e2530d59d8906d78574c3fcee81f16ee473334e6 Mon Sep 17 00:00:00 2001 From: Suraj Pillai <85.suraj@gmail.com> Date: Sat, 20 May 2023 20:47:06 -0400 Subject: [PATCH] Bug fix for state not resetting and rename inner classes (#21) * Bug fix for state not resetting We had a bug with state not resetting after each method chain was completed. This fixes that and adds tests to ensure the behavior. * Rename inner classes Rename inner classes and add more asserts --- .../main/default/classes/UniversalMocker.cls | 86 +++++++++++-------- .../classes/UniversalMocker.cls-meta.xml | 2 +- .../classes/example/AccountDomainTest.cls | 35 +++++++- 3 files changed, 82 insertions(+), 41 deletions(-) diff --git a/force-app/main/default/classes/UniversalMocker.cls b/force-app/main/default/classes/UniversalMocker.cls index ce351d0..bd40e22 100755 --- a/force-app/main/default/classes/UniversalMocker.cls +++ b/force-app/main/default/classes/UniversalMocker.cls @@ -31,10 +31,10 @@ public with sharing class UniversalMocker implements System.StubProvider { Map> mutatorMap = new Map>(); // Inner class instances - private SetupMode_Entry setupAInstance; - private AssertMode_Entry assertAInstance; - private AssertMode_Midway assertBInstance; - private GetParamsMode_Entry getParamsAInstance; + private InitialSetupState setupAInstance; + private InitialValidationState assertAInstance; + private IntermediateValidationState assertBInstance; + private InitialParamValidationState getParamsAInstance; private enum Modes { SETUP, @@ -60,19 +60,19 @@ public with sharing class UniversalMocker implements System.StubProvider { return Test.createStub(this.mockedClass, this); } - public class SetupMode_Entry extends SetupMode_Midway { - private SetupMode_Entry(UniversalMocker parent) { + public class InitialSetupState extends IntermediateSetupState { + private InitialSetupState(UniversalMocker parent) { super(parent); } - public SetupMode_Midway withParamTypes(List paramTypes) { + public IntermediateSetupState withParamTypes(List paramTypes) { this.parent.withParamTypes(paramTypes); - return (SetupMode_Midway) this; + return (IntermediateSetupState) this; } } - public virtual class SetupMode_Midway { + public virtual class IntermediateSetupState { private final UniversalMocker parent; - private SetupMode_Midway(UniversalMocker parent) { + private IntermediateSetupState(UniversalMocker parent) { this.parent = parent; } public void thenReturnVoid() { @@ -81,7 +81,7 @@ public with sharing class UniversalMocker implements System.StubProvider { public void thenReturn(Object returnObject) { this.parent.thenReturn(returnObject); } - public SetupMode_Midway mutateWith(Mutator mutatorInstance) { + public IntermediateSetupState mutateWith(Mutator mutatorInstance) { this.parent.mutateWith(mutatorInstance); return this; } @@ -90,30 +90,30 @@ public with sharing class UniversalMocker implements System.StubProvider { } } - public class AssertMode_Entry { + public class InitialValidationState { private final UniversalMocker parent; - private AssertMode_Entry(UniversalMocker parent) { + private InitialValidationState(UniversalMocker parent) { this.parent = parent; } - public AssertMode_Midway method(String methodName) { + public IntermediateValidationState method(String methodName) { parent.method(methodName); return parent.assertBInstance; } } - public class AssertMode_Midway extends AssertMode_Exit { - private AssertMode_Midway(UniversalMocker parent) { + public class IntermediateValidationState extends FinalValidationState { + private IntermediateValidationState(UniversalMocker parent) { super(parent); } - public AssertMode_Exit withParamTypes(List paramTypes) { + public FinalValidationState withParamTypes(List paramTypes) { parent.withParamTypes(paramTypes); - return (AssertMode_Exit) this; + return (FinalValidationState) this; } } - public virtual class AssertMode_Exit { + public virtual class FinalValidationState { private final UniversalMocker parent; - private AssertMode_Exit(UniversalMocker parent) { + private FinalValidationState(UniversalMocker parent) { this.parent = parent; } public void wasCalled(Integer expectedCallCount, Times assertTypeValue) { @@ -127,29 +127,29 @@ public with sharing class UniversalMocker implements System.StubProvider { } } - public class GetParamsMode_Entry extends GetParamsMode_Midway { - private GetParamsMode_Entry(UniversalMocker parent) { + public class InitialParamValidationState extends IntermediateParamValidationState { + private InitialParamValidationState(UniversalMocker parent) { super(parent); } - public GetParamsMode_Midway withParamTypes(List paramTypes) { + public IntermediateParamValidationState withParamTypes(List paramTypes) { parent.withParamTypes(paramTypes); - return (GetParamsMode_Midway) this; + return (IntermediateParamValidationState) this; } } - public virtual class GetParamsMode_Midway extends GetParamsMode_Exit { - private GetParamsMode_Midway(UniversalMocker parent) { + public virtual class IntermediateParamValidationState extends FinalParamValidationState { + private IntermediateParamValidationState(UniversalMocker parent) { super(parent); } - public GetParamsMode_Exit andInvocationNumber(Integer invocation) { + public FinalParamValidationState andInvocationNumber(Integer invocation) { parent.andInvocationNumber(invocation); - return (GetParamsMode_Exit) this; + return (FinalParamValidationState) this; } } - public virtual class GetParamsMode_Exit { + public virtual class FinalParamValidationState { private final UniversalMocker parent; - private GetParamsMode_Exit(UniversalMocker parent) { + private FinalParamValidationState(UniversalMocker parent) { this.parent = parent; } public Object getValueOf(String paramName) { @@ -160,7 +160,7 @@ public with sharing class UniversalMocker implements System.StubProvider { } } - public SetupMode_Entry when(String stubbedMethodName) { + public InitialSetupState when(String stubbedMethodName) { this.currentMethodName = stubbedMethodName; return this.setupAInstance; } @@ -192,11 +192,11 @@ public with sharing class UniversalMocker implements System.StubProvider { return returnValue; } - public AssertMode_Entry assertThat() { + public InitialValidationState assertThat() { return this.assertAInstance; } - public GetParamsMode_Entry forMethod(String stubbedMethodName) { + public InitialParamValidationState forMethod(String stubbedMethodName) { this.currentMethodName = stubbedMethodName; return this.getParamsAInstance; } @@ -238,6 +238,7 @@ public with sharing class UniversalMocker implements System.StubProvider { if (!this.callCountsMap.containsKey(key)) { this.callCountsMap.put(key, 0); } + this.reset(); } private void thenThrow(Exception exceptionToThrow) { @@ -258,6 +259,7 @@ public with sharing class UniversalMocker implements System.StubProvider { //Integer actualCallCount = this.callCountsMap.get(currentKey); Integer actualCallCount = this.getCallCountsMapInternal().get(currentKey); String methodName = this.currentMethodName; + this.reset(); switch on assertTypeValue { when OR_LESS { system.assert(this.expectedCallCount >= actualCallCount, this.getMethodCallCountAssertMessage(methodName, 'less than or equal')); @@ -275,6 +277,7 @@ public with sharing class UniversalMocker implements System.StubProvider { String currentKey = this.getCurrentKey(); Integer actualCallCount = this.getCallCountsMapInternal().get(currentKey); String methodName = this.currentMethodName; + this.reset(); if (actualCallCount != null) { this.expectedCallCount = 0; system.assertEquals(this.expectedCallCount, actualCallCount, String.format('Method {0} was called 1 or more times', new List{ methodName })); @@ -292,18 +295,20 @@ public with sharing class UniversalMocker implements System.StubProvider { throw new IllegalArgumentException(String.format('Param name {0} not found for the method {1}', new List{ paramName, this.currentMethodName })); } Object returnValue = paramsMap.get(paramName.toLowerCase()); + this.reset(); return returnValue; } private Map getArgumentsMap() { String theKey = this.getCurrentKey(); Map returnValue = this.getArgumentsMapInternal().get(theKey).get(this.forInvocationNumber); + this.reset(); return returnValue; } private String getCurrentKey() { String retVal = this.currentMethodName; - if (this.currentParamTypesString != null) { + if (!String.isEmpty(this.currentParamTypesString)) { retVal += KEY_DELIMITER + this.currentParamTypesString; } return retVal.toLowerCase(); @@ -372,10 +377,15 @@ public with sharing class UniversalMocker implements System.StubProvider { } private void initInnerClassInstances() { - this.setupAInstance = new SetupMode_Entry(this); - this.assertAInstance = new AssertMode_Entry(this); - this.assertBInstance = new AssertMode_Midway(this); - this.getParamsAInstance = new GetParamsMode_Entry(this); + this.setupAInstance = new InitialSetupState(this); + this.assertAInstance = new InitialValidationState(this); + this.assertBInstance = new IntermediateValidationState(this); + this.getParamsAInstance = new InitialParamValidationState(this); + } + + private void reset() { + this.currentParamTypesString = ''; + this.currentMethodName = ''; } /* End Private Methods */ diff --git a/force-app/main/default/classes/UniversalMocker.cls-meta.xml b/force-app/main/default/classes/UniversalMocker.cls-meta.xml index 871a8cf..1248daa 100755 --- a/force-app/main/default/classes/UniversalMocker.cls-meta.xml +++ b/force-app/main/default/classes/UniversalMocker.cls-meta.xml @@ -1,5 +1,5 @@ - 53.0 + 56.0 Active diff --git a/force-app/main/default/classes/example/AccountDomainTest.cls b/force-app/main/default/classes/example/AccountDomainTest.cls index 515dd8c..176baba 100644 --- a/force-app/main/default/classes/example/AccountDomainTest.cls +++ b/force-app/main/default/classes/example/AccountDomainTest.cls @@ -5,9 +5,9 @@ public with sharing class AccountDomainTest { private static final AccountDomain sut; // system under test static { - mockService = UniversalMocker.mock(AccountDBService.class); + mockService = UniversalMocker.mock(AccountDBService.class); //This is the service we are mocking mockServiceStub = (AccountDBService) mockService.createStub(); - sut = new AccountDomain(mockServiceStub); + sut = new AccountDomain(mockServiceStub); //This is the class into which we inject our mocked service } @IsTest @@ -102,6 +102,37 @@ public with sharing class AccountDomainTest { System.assertEquals(acctTwo.Name, acctsWithMatchingName[0].Name); } + @IsTest + public static void shouldResetMethodAndParamsAfterEachChain() { + //setup + String mockedMethodName = 'getMatchingAccounts'; + String newMethodName = 'getOneAccount'; + Account acctOne = new Account(Name = 'Account with matching Id'); + Account acctTwo = new Account(Name = 'Account with matching name'); + + mockService.when(mockedMethodName).withParamTypes(new List{ Id.class }).thenReturn(new List{ acctOne }); + mockService.when(newMethodName).thenReturn(acctTwo); //This method takes no params. So by mocking this we attempt to ensure that the param type list from previous mock call (Id.class) has been cleared out + + //test + Test.startTest(); + Id mockAccountId = '001000000000001'; + List acctsWithMatchingId = sut.getMatchingAccounts(mockAccountId); + Account anotherAccount = sut.getAccountDetail(); + Test.stopTest(); + + //verify + mockService.assertThat().method(mockedMethodName).withParamTypes(new List{ Id.class }).wasCalled(1); + mockService.assertThat().method(newMethodName).wasCalled(1); + + System.assertEquals(acctOne.Name, acctsWithMatchingId[0].Name); + System.assertEquals(acctTwo.Name, anotherAccount.Name); + + Id acctIdParam = (Id) mockService.forMethod(mockedMethodName).withParamTypes(new List{ Id.class }).getValueOf('accountId'); + Map argsMap = mockService.forMethod(newMethodName).getArgumentsMap(); + Assert.areEqual(mockAccountId, acctIdParam); + Assert.areEqual(0, argsMap.size()); + } + @IsTest public static void it_should_throw_mock_exception() { //setup