*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.

Reply via email to