Closed cropredy closed 6 years ago
Hi, what you are describing looks a perfect fit for the fflib-Answer . V
On Fri, 15 Sep 2017 at 18:41, cropredy notifications@github.com wrote:
I'll be the first to admit I'm no expert in ApexMocks but do understand fflib_ApexCommon quite well
Class/Method under test - inserts an SObject and then uses the inserted SObject's ID to call an email service. Example is simplified from real work requirement
public class Foo { public void doWork() { fflib_ISobjectUnitOfWork uow = Application.UnitOfWork.newInstance(); Account a = new Account(Name='A0', Website = 'www.salesforce.com'); uow.registerNew(a); uow.commitWork(); EmailService.sendEmail(a.Id); // relies on commitWork inserting the Account } }
TestMethod
private class TestApexMocks { @isTest private static void testFoo() { fflib_ApexMocks mocks = new fflib_ApexMocks(); // Given mock implementation of UnitOfWork fflib_SobjectUnitOfWork mockUow = (fflib_SobjectUnitOfWork) mocks.mock(fflib_SObjectUnitOfWork.class); Application.UnitOfWork.setMock(mockUow);
// Given mock implementation of EmailService EmailServiceImpl mockEmailSvc = (EmailServiceImpl) mocks.mock(EmailServiceImpl.class); Application.Service.setMock(IEmailService.class,mockEmailSvc); // When method invoked new Foo().doWork(); // Then verify EmailService called with inserted Account ID - How?? ((EmailServiceImpl) mocks.verify(mockEmailSvc,mocks.times(1))) .sendEmail(??);
}
Essentially the issue is that uow.commitWork() is a void method so thenReturn doesn't help. uow.commitWork() has a side effect, new SObjects get IDs - but if you are mocking uow, how does one mock that side effect so the code under test gets that ID in variable a?
The meta comment here is that unit testing methods that use the Unit of Work layer is difficult when the code relies on the values of inserted sobjects to do further work such as in my EmailService example, or calling an async method like future or queueable. AFAIK, you can't verify the payloads to these follow-on services if those payloads include IDs from the committed new SObjects.
I remain tantalized by ApexMocks to make my tests faster and easier to set up but figuring out how to verify when no real DML is being done by the testmethod is perplexing/challenging.
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/financialforcedev/fflib-apex-mocks/issues/52, or mute the thread https://github.com/notifications/unsubscribe-auth/AS4EDy_vvCD10igiZI1Hr11i8XXKn0xIks5sira3gaJpZM4PZSzS .
aha - this is where not having any previous background with Mockito is biting me; I found this blog post https://xonoxforce.wordpress.com/2017/03/31/answering-with-apex-mocks/ - I'm guessing this is you ? Well, this should be fun to try.
the andyinthecloud blog should be extended to illustrate more use cases with ApexMocks, Sobjects, and fflib. The examples we have today are too simple once you start using ApexMocks for real world cases
On Fri, Sep 15, 2017 at 11:23 AM, Enzo Denti notifications@github.com wrote:
Hi, what you are describing looks a perfect fit for the fflib-Answer . V
On Fri, 15 Sep 2017 at 18:41, cropredy notifications@github.com wrote:
I'll be the first to admit I'm no expert in ApexMocks but do understand fflib_ApexCommon quite well
Class/Method under test - inserts an SObject and then uses the inserted SObject's ID to call an email service. Example is simplified from real work requirement
public class Foo { public void doWork() { fflib_ISobjectUnitOfWork uow = Application.UnitOfWork.newInstance(); Account a = new Account(Name='A0', Website = 'www.salesforce.com'); uow.registerNew(a); uow.commitWork(); EmailService.sendEmail(a.Id); // relies on commitWork inserting the Account } }
TestMethod
private class TestApexMocks { @isTest private static void testFoo() { fflib_ApexMocks mocks = new fflib_ApexMocks(); // Given mock implementation of UnitOfWork fflib_SobjectUnitOfWork mockUow = (fflib_SobjectUnitOfWork) mocks.mock(fflib_SObjectUnitOfWork.class); Application.UnitOfWork.setMock(mockUow);
// Given mock implementation of EmailService EmailServiceImpl mockEmailSvc = (EmailServiceImpl) mocks.mock(EmailServiceImpl.class); Application.Service.setMock(IEmailService.class,mockEmailSvc);
// When method invoked new Foo().doWork();
// Then verify EmailService called with inserted Account ID - How?? ((EmailServiceImpl) mocks.verify(mockEmailSvc,mocks.times(1))) .sendEmail(??);
}
Essentially the issue is that uow.commitWork() is a void method so thenReturn doesn't help. uow.commitWork() has a side effect, new SObjects get IDs - but if you are mocking uow, how does one mock that side effect so the code under test gets that ID in variable a?
The meta comment here is that unit testing methods that use the Unit of Work layer is difficult when the code relies on the values of inserted sobjects to do further work such as in my EmailService example, or calling an async method like future or queueable. AFAIK, you can't verify the payloads to these follow-on services if those payloads include IDs from the committed new SObjects.
I remain tantalized by ApexMocks to make my tests faster and easier to set up but figuring out how to verify when no real DML is being done by the testmethod is perplexing/challenging.
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/financialforcedev/fflib-apex-mocks/issues/52, or mute the thread https://github.com/notifications/unsubscribe-auth/AS4EDy_ vvCD10igiZI1Hr11i8XXKn0xIks5sira3gaJpZM4PZSzS .
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/financialforcedev/fflib-apex-mocks/issues/52#issuecomment-329862744, or mute the thread https://github.com/notifications/unsubscribe-auth/ACNrcqNq_CDiQPMYNpJ-mV8QSsBZ9l7Dks5sisCxgaJpZM4PZSzS .
@cropredy will do, thanks for the nudge! 👍
I'll be the first to admit I'm no expert in ApexMocks but do understand fflib_ApexCommon quite well
Class/Method under test - inserts an SObject and then uses the inserted SObject's ID to call an email service. Example is simplified from real work requirement
TestMethod
Essentially the issue is that uow.commitWork() is a void method so
thenReturn
doesn't help.uow.commitWork()
has a side effect, new SObjects get IDs - but if you are mockinguow
, how does one mock that side effect so the code under test gets that ID in variablea
?The meta comment here is that unit testing methods that use the Unit of Work layer is difficult when the code relies on the values of inserted sobjects to do further work such as in my EmailService example, or calling an async method like future or queueable. AFAIK, you can't verify the payloads to these follow-on services if those payloads include IDs from the committed new SObjects.
I remain tantalized by ApexMocks to make my tests faster and easier to set up but figuring out how to verify when no real DML is being done by the testmethod is perplexing/challenging.