*Thanks for this.*
*What it boils down to for me is having a better reasoning for this suggestion from CodeReviewComments:* *“The implementing package should return concrete (usually pointer or struct) types”* *And that’s the reasoning:* *“that way, **new methods can be added** to implementations without requiring extensive refactoring”* *Even if you would return an interface rather than a concrete type when adding new methods to it you do not have to refactor any client packages. So why is it that “extensive refactoring” is required in this case? * On Tuesday, July 31, 2018 at 7:15:53 PM UTC+2, Jake Montgomery wrote: > > I'm sure everyone has their own opinion, but here are some ideas. First > your final question: > > >> If so, what are the downsides of having z returning an interface instead >> of a concrete type >> > > I think the link > <https://github.com/golang/go/wiki/CodeReviewComments#interfaces>you > provided covers that: > > *"The implementing package should return concrete (usually pointer or > struct) types: that way, new methods can be added to implementations > without requiring extensive refactoring."* > > I would stick with that advice pretty much across the board. I would also > resist the urge to define a single interface for a,b and c to use. > > Code duplication because the interface ZClient is implemented in all the >> depending packages with the test fixtures for it. >> >> It is very easy to end up with the same mocking code in different >> packages. >> > > Small amounts of code duplication are ok, and even part of go philosophy. > I know that runs counter to the philosophy of many other languages. So if > the overhead of mocking is small, or the needs of a, b and c vary, then I > would stick with the separate implementations of the mock code/ > > Maintainability >> >> When refactoring package z, client side testing code has to be adjusted >> in all the depending packages. >> > > > This is a bit of a red herring. If z is refactored internally, then the > public API will not change, so there should be no need to adjust the a,b > and c tests or their mocks. If, OTOH, you are refactoring the *public > *interface > if z, then you will, presumably also need to adjust the a, b and c code. So > a little adjusting of their tests is just part of that. Really, breaking > changes to the public API of a package should be avoided anyway. So by > coding to make that easier you are really coding for failure. (This talk > by Rich Hickey <https://www.youtube.com/watch?v=oyLBGkS5ICk> about > breaking changes is not about go, but is worth watch.) > > > So. If a,b and c are public libraries, I would try to stick with the > separate mocking, as you describe. (Public here means truly public, or > widely used within a large organization.) If, on the other hand, a, b and c > are all packages that serve a single final executable, or possibly even a > small suite of closely related executables, all maintained by the same > development group, then you might take a more pragmatic approach, while > still maintaining good practices. Given my comments above I would still > default to keeping it all separate until it is clear that it is creating a > real burden. > > So, if the mocking requires non-trivial amounts of code, and the > conditions above are met, you could consider creating a separate package > that contains the z-mock helpers. That package can be imported by a, b and > c. If you do that, try to code the mock package using good library package > design practices. And I would have the z-mock functions return concrete > types, as described in > https://github.com/golang/go/wiki/CodeReviewComments#interfaces > <https://www.google.com/url?q=https%3A%2F%2Fgithub.com%2Fgolang%2Fgo%2Fwiki%2FCodeReviewComments%23interfaces&sa=D&sntz=1&usg=AFQjCNGc4nPX9iBqAd6W2BPzcz80Tu-mLQ>. > > As long as it implements the same functions as z, then it will also fulfill > the interfaces that a,b and c take. > > Good luck. > > On Monday, July 30, 2018 at 3:51:25 AM UTC-4, Michael Gross wrote: >> >> Hello list, >> >> I have a question about testing packages in conjunction with the general >> recommendations from >> >> https://github.com/golang/go/wiki/CodeReviewComments >> >> Suppose we have packages a,b and c which depend on a package z. Say z >> implements all the necessary unit and integration tests it needs to test >> itself. >> >> Farther more it has a factory 'func New() z.Client' returning a client >> which all the depending packages use. >> >> Following these recommendations >> >> https://github.com/golang/go/wiki/CodeReviewComments#interfaces >> >> z.Client is implemented as a struct >> >> Say z.Client has one method which all the depending packages use >> >> func Request(o Opts) map[string]interface{} >> >> In order to test a, b and c a mock implementation of z.Client is needed. >> >> Still following the CodeReviewComments recommendations we implement in >> each of the depending packages a,b and c this interface >> >> type ZClient interface { >> >> Request(o Opts) map[string]interface{} >> >> } >> >> and code against it. >> >> Now when writing the tests for the packages a,b and c since the returned >> map of the request call is general we use fixtures >> >> implementing the required cases. >> >> stuff like >> >> r := c.EXPECTRequest(gmock.Any()).Return(map[string]interface{}{ >> >> `special_flag_a` : true, >> >> `treat_this_as_an_error` : `timeout`, >> >> }) >> >> IMO there are several down sides to this approach >> >> Code duplication because the interface ZClient is implemented in all the >> depending packages with the test fixtures for it. >> >> It is very easy to end up with the same mocking code in different >> packages. >> >> Maintainability >> >> When refactoring package z, client side testing code has to be adjusted >> in all the depending packages. >> >> So is this the suggested way of implementing this? >> >> If so, what are the downsides of having z returning an interface instead >> of a concrete type and have the package also implement a public mock >> >> with corresponding fixtures? >> >> -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.