You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository has been archived by the owner on Jun 27, 2023. It is now read-only.
I am not sure if GoMock supports this natively or not. If it does, it would be nice if the documentation reflected how to do interaction testing more clearly. Interaction testing entails validating how a function is called, wherein a test should fail if a function isn’t called the right way.
The idea is that independent of the recorded expectations that one has the ability to verify that certain calls were made or not made, maybe ignoring the how other mocks associated with the controller are used.
This is partially expressable in GoMock today with the use of (*gomock.Controller).Finish, but it covers all mocks attached to that controller, meaning target verification is not possible.
This is a standard capability of other mocking suites. If we take a look at Mockito, we can achieve targeted interaction testing with terminal statements as follows:
DatabasemockDb = mock(Database.class); // create mockAuthorizermockAuth = mock(Authorizer.class); // create mocksut.operate(mockDb, mockAuth); // use mockverify(mockDb).PurgeEntries(); // only care that precisely this method is called// no desire to verify mockAuth
I do not have a strong opinion on what the API should look like. Perhaps:
ctrl:=gomock.NewController(t)
mockDB:=mockdatabase.NewMockDatabase(ctrl) // verify only this onemockAuth:=mockauthorizer.NewMockAuthorizer(ctrl)
sut.Operate(mockDB, mockAuth)
ctrl.Finish()
mockDB.VERIFY().PurgeEntries()
Why the feature is needed
Targeted interaction testing is bread and butter feature of mocking support libraries since time memorial. I appreciate that (*gomock.Controller).Finish can be used for validating ALL mocks within its scope, but that is unfortunately means I still need to record behavior (beyond mere classic stub returns) for all mock-based test doubles. That can get very fragile quickly, which is where the targeted verification comes in.
(Optional) Proposed solution A clear description of a proposed method for
adding this feature to gomock.
I presume gomock.callSet would gain a new field for observed calls that basically appends all observed calls thereto:
typeobservedCallstruct {
KeycallSetKeyCall*Call
}
// callSet represents a set of expected calls, indexed by receiver and method// name.typecallSetstruct {
// Calls that are still expected.expectedmap[callSetKey][]*Call// Calls that have been exhausted.exhaustedmap[callSetKey][]*Call// NEW// Calls that have been exhausted.observed []*observedCall
}
The Verify API would then consult observed and could perform presence, ordering, parameter, etc. validation.
Thank you for your consideration! I am happy to review code or design. I want to see this happen.
The text was updated successfully, but these errors were encountered:
Thank you for your feature request. To me this sounds a lot like #7 but a different API for the same result, correct me if I am wrong. This sort of thing can sort of be done today, but you would need to explicitly have a AnyTimes() expected call for each method that you don't want to "verify". I like personally like this explicitness but I understand the point that you may want to save a few extra lines of code in some cases.
If we did go with an approach like this is there a reason for VERIFY() to operate outside the scope of Finish()?
Thank you for your feature request. To me this sounds a lot like #7 but a different API for the same result, correct me if I am wrong.
On a facial look, it does appear similar to #7. I am not too tied toward any API prescription so long as whatever is used is clear.
This sort of thing can sort of be done today, but you would need to explicitly have a AnyTimes() expected call for each method that you don't want to "verify". I like personally like this explicitness but I understand the point that you may want to save a few extra lines of code in some cases.
I do like explicitness as well personally, but this is not so much for me but rather to present GoMock itself in a technical documentation (cookbook) context at-parity with several other mocking libraries. Roughly what I think I would expect is that for each call to an unverified mock that such a mock would instead return the zero value responses for its given return values (a classical, dumb stub).
If we did go with an approach like this is there a reason for VERIFY() to operate outside the scope of Finish()?
That is a good question. I suspect that unfortunately though a mock-level attribute of {strict | loose} may still be too broad. Imagine I have a mock that has been given a set of recorded call and responses, but I really only care that a single thing has occurred for verification, leaving the rest to basically a "stub" like performance:
// Pardon the bad snippet. It's late here, and I'm tired.typeUnderTeststruct{}
func (sutUnderTest) Operate(dbDatabase, authAuthorizer) {
if!auth.IsSuperUser() {
return
}
db.PurgeEntries()
ifauth.HasAttribute(authorization.MayDance) {
dancelibrary.DoAJigOn(db) // I do not want to care about this.
}
}
funcTest(t*testing.T) {
ctrl:=gomock.NewController(t)
mockDB:=mockdatabase.NewMockDatabase(ctrl) // verify only this onemockAuth:=mockauthorizer.NewMockAuthorizer(ctrl)
sut.Operate(mockDB, mockAuth)
ctrl.Finish()
mockDB.VERIFY().PurgeEntries() // Actually important.
}
I might not ever want to have to care that DoAJigOn with whatever it does to Database is a possibility, because package dancelibrary is externally defined and owned, making my test fragile or overly specified.
Requested feature
I am not sure if GoMock supports this natively or not. If it does, it would be nice if the documentation reflected how to do interaction testing more clearly. Interaction testing entails validating how a function is called, wherein a test should fail if a function isn’t called the right way.
The idea is that independent of the recorded expectations that one has the ability to verify that certain calls were made or not made, maybe ignoring the how other mocks associated with the controller are used.
This is partially expressable in GoMock today with the use of
(*gomock.Controller).Finish
, but it covers all mocks attached to that controller, meaning target verification is not possible.This is a standard capability of other mocking suites. If we take a look at Mockito, we can achieve targeted interaction testing with terminal statements as follows:
You can see a rough sketch of this here: https://www.baeldung.com/mockito-verify.
I do not have a strong opinion on what the API should look like. Perhaps:
Why the feature is needed
Targeted interaction testing is bread and butter feature of mocking support libraries since time memorial. I appreciate that
(*gomock.Controller).Finish
can be used for validating ALL mocks within its scope, but that is unfortunately means I still need to record behavior (beyond mere classic stub returns) for all mock-based test doubles. That can get very fragile quickly, which is where the targeted verification comes in.(Optional) Proposed solution A clear description of a proposed method for
adding this feature to gomock.
I presume
gomock.callSet
would gain a new field for observed calls that basically appends all observed calls thereto:The
Verify
API would then consultobserved
and could perform presence, ordering, parameter, etc. validation.Thank you for your consideration! I am happy to review code or design. I want to see this happen.
The text was updated successfully, but these errors were encountered: