Comments (16)
Great writeup, thanks Eric!
For your specific case, you could use the sobjectWithId matcher. But I understand your general sentiment. It's a legitimate concern, but still kind of funny 🤣.
Recreating the exception is trivial.
Account a = new Account();
a.get(Case.Id);
Or the similar, SObject row was retrieved via SOQL without querying the requested field
exception, even if the field belongs to the object.
for (Account a: [SELECT Id FROM Account]) {
a.get(Account.Name);
}
Like you say, it's WAD. The matchers naively try to retrieve all the field values from all the SObject records, silently swallowing up the inevitable spurious exceptions.
So what to do..
As a workaround, perhaps use a captor or a custom matcher instead?
But in ApexMocks itself.... You say we can't be more selective with the object type corresponding to the SObjectFields. But perhaps we can. We just need to supply the map as something that does have an associated SObjectType.... perhaps an SObject? :)
public class SObjectWith implements fflib_IMatcher
{
private SObject toMatch;
public SObjectWith(SObject toMatch)
{
this.toMatch = validate(toMatch);
}
public Boolean matches(Object arg)
{
if (arg != null && arg instanceof SObject)
{
SObject soArg = (SObject)arg;
if (soArg.getSObjectType() != this.toMatch.getSObjectType())
{
return false;
}
if (!sobjectMatches(soArg, this.toMatch.getPopulatedFieldsAsMap()))
{
return false;
}
return true;
}
return false;
}
}
If you want to submit a PR along those lines, I'll be happy to review (also to include a version for a List). Otherwise, I'll try and get this in at some point.
from fflib-apex-mocks.
This is pretty clever; of course the old constructor that supports a map argument will need to continue to be supported.
from fflib-apex-mocks.
Hi team, any progress on this item? We are using mocks for integration tests. That is, the unit of work contains different object types. However, it appears we can not use mocks because of this limitation. Thank you!
from fflib-apex-mocks.
@bradedge -- Can you post a working example somewhere for us to review and investigate with?
from fflib-apex-mocks.
In our main class we have:
uow.registerDirty(transObj);
uow.registerDirty(invItemObj);
In our test class, this verify works:
((IApplicationSObjectUnitOfWork)
mocks.verify(uowMock, mocks.times(3).description('Expected 3 transaction updated.'))).registerDirty(
fflib_Match.sObjectWith(
new Map<SObjectField, Object>{
Transaction__c.Order__c => orderList[0].Id
} ));
This next verify throws an error:
((IApplicationSObjectUnitOfWork)
mocks.verify(uowMock, mocks.times(1).description('Expected 1 invoice item updated.'))).registerDirty(
fflib_Match.sObjectWith(
new Map<SObjectField, Object>{
Invoice_Item__c.Order__c => orderList[0].Id,
} ));
Error message:
fflib_ApexMocks.ApexMocksException: Expected : 1, Actual: 0 -- Wanted but not invoked IApplicationSObjectUnitOfWork__sfdc_ApexStub.registerDirty(SObject)
The log file shows:
System.SObjectException: Invoice_Item__c.Order__c does not belong to SObject type Transaction__c
from fflib-apex-mocks.
@bradedge
Is a stacktrace available for the error as well, indicating where in the FFLIB code the error is occurring? Thanks.
from fflib-apex-mocks.
@bradedge The exception is normal in the debug log, the ApexMocks eats this error (you can see in the code). Have you looked at Why Aren't My ApexMocks working?.
I would say that invItemObj
does not have field Order__c
set to orderList[0].Id
or, by the time the mocks.verify is executed, you've cleared/changed the value of Order__c
from fflib-apex-mocks.
@cropredyHelix, thank you. We have been through "Why Aren't My ApexMocks working?".
When we read the issue you originally posted above, it describes the behavior we are getting and leads me to believe that mocks will not allow us to verify when we have multiple object types in the UOW (for example, in integration tests that perform actions on many object types).
Am incorrect? Does mocks allow us to verify multiple object types and you suspect we have an error elsewhere?
from fflib-apex-mocks.
I would appreciate some syntax help in a verify statement, to get through this item...
We have successfully verified objects in the unit of work that were added using fflib_SObjectUnitOfWork.registerNew(SObject record) using this statement:
((IApplicationSObjectUnitOfWork)
mocks.verify(uowMock, mocks.times(2).description(
'Expected 2 invoices.'))).registerNew(
fflib_Match.sObjectWith(
new Map<SObjectField, Object>{
Invoice__c.Order__c => orderList[0].Id
}
)
);
However, this syntax does not work for records that were created using the overloaded "registerNew(SObject record, Schema.sObjectField relatedToParentField, SObject relatedToParentRecord)".
How do I match against items in the overloaded registerNew method? Thank you
from fflib-apex-mocks.
@bradedge,
In an earlier post, I commented that a stacktrace would be helpful in pinpointing the issue. Without, a probable cause was located, and a stracktrace could verify. Thanks.
from fflib-apex-mocks.
Failing on:
((IApplicationSObjectUnitOfWork)
mocks.verify(uowMock, mocks.times(2).description(
'Expected 2 invoice items created for transList[0] and transList[2] (which goes on a new invoice and invoice item).'))).registerNew(
fflib_Match.sObjectWith(
new Map<SObjectField, Object>{
Invoice_Item__c.Unit_Price__c => 5
}
)
);
Stack trace:
Class.fflib_MethodVerifier.throwException: line 81, column 1
Class.fflib_AnyOrder.verify: line 45, column 1
Class.fflib_MethodVerifier.verifyMethodCall: line 20, column 1
Class.fflib_ApexMocks.verifyMethodCall: line 139, column 1
Class.fflib_ApexMocks: line 266, column 1
Class.fflib_ApexMocks: line 87, column 1
Class.IApplicationSObjectUnitOfWork__sfdc_ApexStub.registerNew: line 241, column 1
Class.InvoiceTransactionMockTest.singleOrderAndTranscationScenario1: line 145, column 1
12:40:55.0 (662859775)|FATAL_ERROR|fflib_ApexMocks.ApexMocksException: Expected : 2, Actual: 0 -- Wanted but not invoked: IApplicationSObjectUnitOfWork__sfdc_ApexStub.registerNew(SObject). Expected 2 invoice items created for transList[0] and transList[2] (which goes on a new invoice and invoice item).
from fflib-apex-mocks.
@bradedge,
That stacktrace appears related to the Assertion failure. You mentioned an exception detailed in the log for "System.SObjectException: Invoice_Item__c.Order__c does not belong to SObject type Transaction__c". Does a stacktrace exist for that? Thanks again.
from fflib-apex-mocks.
- You can definitely use UnitOfWork on multiple SobjectTypes and verify results using ApexMocks. Our org's code does this in numerous places
- If you want to mock against
registerNew(SObject record, Schema.sObjectField relatedToParentField, SObject relatedToParentRecord)
...
((IApplicationSObjectUnitOfWork)
mocks.verify(uowMock, mocks.times(2).description(
'Expected invoice items created for transList[0] and [2] each with Unit Price of 5.00')))
.registerNew(
fflib_Match.sObjectWith(
new Map<SObjectField, Object>{
Invoice_Item__c.Unit_Price__c => 5
}
),
fflib_Match.eqSObjectField(Invoice_Item__c.Transaction__c),
fflib_Match.sObjectOfType(Transaction__c.SobjectType)
);
Now, if you are verifying that only Trans[0] and Trans[2] are linked, you'll need two different mocks.verify
For the first Invoice Item
((IApplicationSObjectUnitOfWork)
mocks.verify(uowMock, mocks.times(1).description(
'Expected invoice items created for transList[0] with Unit Price of 5.00')))
.registerNew(
fflib_Match.sObjectWith(
new Map<SObjectField, Object>{
Invoice_Item__c.Unit_Price__c => 5
}
),
fflib_Match.eqSObjectField(Invoice_Item__c.Transaction__c),
fflib_Match.sObjectWith(
new Map<SObjectField, Object>{
Transaction__c.Id => transList[0].Id
}
)
);
For the second item
((IApplicationSObjectUnitOfWork)
mocks.verify(uowMock, mocks.times(1).description(
'Expected invoice items created for transList[2] with Unit Price of 5.00')))
.registerNew(
fflib_Match.sObjectWith(
new Map<SObjectField, Object>{
Invoice_Item__c.Unit_Price__c => 5
}
),
fflib_Match.eqSObjectField(Invoice_Item__c.Transaction__c),
fflib_Match.sObjectWith(
new Map<SObjectField, Object>{
Transaction__c.Id => transList[2].Id
}
)
);
Now, perhaps I'm not understanding your use case but what you are trying to do is eminently doable. Each mocks.verify uses matchers against the method signature. If you use matchers for one arg, you have to use matchers for all args.
from fflib-apex-mocks.
@cropredyHelix that resolved our issue. Thank you all for the support and help through this! Also, thank you for supporting the community on this killer framework.
from fflib-apex-mocks.
Thanks all for pitching in here
from fflib-apex-mocks.
@daveespo - not sure why this was closed as while we solved @bradedge issue, the underlying issue in OP was flagged as an enhancement by @dfruddffdc 2018-02-21. Was the enhancement ever implemented? (perhaps in some other Issue)
from fflib-apex-mocks.
Related Issues (20)
- Explore the feasibility to support @NamespaceAccessible HOT 1
- How to use Apex Mock Framework for Custom Setting Records? HOT 3
- Heroku error when trying to deploy the repository
- No jar file? HOT 1
- Install help needed HOT 4
- fflib_MyList has 0 coverage when I run MockTest. Is that normal? HOT 1
- Mark all classes as @IsTest?
- makeRelationship does not work with Junction Objects HOT 1
- Add a method to allow us to create any SObjects with any NON WRITABLE Field HOT 2
- How to verify a Method was called N times? HOT 3
- Why do we must pass an Interface to set a service mock? HOT 2
- There is no way to mock void methods HOT 2
- renderStoredEmailTemplate returns with an error System.EmailTemplateRenderException: INVALID_CROSS_REFERENCE_KEY: invalid cross reference id when passing Ids generated from fflib_IDGenerator HOT 1
- README.md out of date? HOT 1
- Deploy to salesforce is not working HOT 12
- Can't deploy to production HOT 2
- Unable to deploy to developer org with Unhandled Exception HOT 1
- Multiple domain mocks HOT 4
- IDGenerator : Generating Salesforce Object ID under the new structure HOT 3
- Code Coverage Issue with fflib_InvocationOnMock Class HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from fflib-apex-mocks.