dependency injection in Go?

4,877 views
Skip to first unread message

touca...@gmail.com

unread,
Mar 31, 2012, 10:26:33 PM3/31/12
to golan...@googlegroups.com
So I've fallen in love with dependency injection and Guice, is there anything in/for Go to facilitate dependency injection?

- Daniel

Lars Pensjö

unread,
Apr 1, 2012, 1:03:00 AM4/1/12
to golan...@googlegroups.com
Don't you get the same functionality with "go test"?

David Symonds

unread,
Apr 1, 2012, 1:04:58 AM4/1/12
to touca...@gmail.com, golan...@googlegroups.com
On Sun, Apr 1, 2012 at 12:26 PM, <touca...@gmail.com> wrote:

> So I've fallen in love with dependency injection and Guice, is there
> anything in/for Go to facilitate dependency injection?

Just write the function/method/whatever such that it takes its
dependencies. There's no need for a fancy framework.


Dave.

David Symonds

unread,
Apr 1, 2012, 1:05:45 AM4/1/12
to Lars Pensjö, golan...@googlegroups.com
On Sun, Apr 1, 2012 at 3:03 PM, Lars Pensjö <lars....@gmail.com> wrote:

> Don't you get the same functionality with "go test"?

That's completely orthogonal to DI. The former runs tests, and the
latter makes it easier to write testable code and its tests.


Dave.

David Anderson

unread,
Apr 1, 2012, 1:18:19 AM4/1/12
to touca...@gmail.com, golan...@googlegroups.com
On Sat, Mar 31, 2012 at 7:26 PM, <touca...@gmail.com> wrote:
So I've fallen in love with dependency injection and Guice, is there anything in/for Go to facilitate dependency injection?

In addition to David's observation, I'll point out: tests in Go have access to the unexported symbols of a package. You can use this fact to inject mocks into the internals of your package for tests, without polluting the external API with a dozen injection parameters. Testing can remain private and out of your documented/supported API.

A mix of judiciously exposing parameters that are useful (e.g. for a protocol, wrap a net.Conn rather than take and pass on parameters to net.Dial) and injecting privately to the package's tests will get you the best of DI and an API that doesn't drive people nuts.

- Dave

Lars Pensjö

unread,
Apr 1, 2012, 2:25:14 AM4/1/12
to golan...@googlegroups.com
Do you mean that "go test" haven't got anything to do with DI? I don't know the term "dependency injection" well, but I do use "go test" for swapping in simplified "mock" implementations of dependent components when testing. Please explain what I am missing. It would seem to me that the "go test" supports what you want to do with DI.

On Sunday, 1 April 2012 07:05:45 UTC+2, David Symonds wrote:

Albert Strasheim

unread,
Apr 1, 2012, 2:32:26 AM4/1/12
to golan...@googlegroups.com
Hello


On Sunday, April 1, 2012 4:26:33 AM UTC+2, touca...@gmail.com wrote:
So I've fallen in love with dependency injection and Guice, is there anything in/for Go to facilitate dependency injection?

You can do all kinds of dependency injection "stuff" using Go's interfaces and embedding.

I can really recommend looking at what can be achieved with a mix of embedding, other features of interfaces, picking good names for your structs and interfaces, splitting your code over packages, designing your New functions, understanding the issues of untagged struct literals and unexported fields and then putting it all together.

You end up with great code and APIs that can be tested (with or without mocks) and reused in any way you can imagine.

You probably don't need a Guice equivalent. At least not yet.

Cheers

Albert

David Symonds

unread,
Apr 1, 2012, 2:32:24 AM4/1/12
to Lars Pensjö, golan...@googlegroups.com
On Sun, Apr 1, 2012 at 4:25 PM, Lars Pensjö <lars....@gmail.com> wrote:

> Do you mean that "go test" haven't got anything to do with DI? I don't know
> the term "dependency injection" well, but I do use "go test" for swapping in
> simplified "mock" implementations of dependent components when testing.
> Please explain what I am missing. It would seem to me that the "go
> test" supports what you want to do with DI.

DI is just a testing technique, or more generally a way to make code
independent of its dependencies. You can write tests with or without
DI, and you can use DI to help testing or for other reasons. There's
nothing for "go test" to support, any more than it needs to support
testing code that uses loops or writing table-driven tests.


Dave.

Florian Weimer

unread,
Apr 1, 2012, 11:44:55 AM4/1/12
to golan...@googlegroups.com
* toucansam:

> So I've fallen in love with dependency injection and Guice<http://code.google.com/p/google-guice/>,

> is there anything in/for Go to facilitate dependency injection?

There are some examples in the standard library which rely on global
variables, notably the http package.

Bikal Gurung

unread,
Apr 1, 2012, 9:50:34 AM4/1/12
to golang-nuts
Hi David,

I think OO concepts/patterns and in particular - repository and DI -
are quite redundant in Go and other functionally oriented languages.
This is because go was expressly designed to reduce inheritance
hierarchy/tyranny/type-system of OO languages/systems. However, since
your concern seems to be mostly about testing go programs, I think you
will benefit more if you develop your programs/functions/packages to
be more side effect free or uses less of global/package variables. But
then again this is true of an OO system as well. Hope this helps.

Bikal

On Apr 1, 7:32 am, David Symonds <dsymo...@golang.org> wrote:

Dougx

unread,
Apr 5, 2012, 4:57:23 AM4/5/12
to golan...@googlegroups.com
Not afaik. Certainly nothing that resembles guice.

If you want to write your own IOC container I'd recommend getting start with interfaces here:

...and then find out about constructors and figure out a std. scheme you want to adhere to:

...and then use something from the "reflect" package to auto-generate arguments:

Haven't seen anyone who's gone down this road so far though, so hm... if I was you I'd start just writing go code and only go down that road if you find yourself in a situation where you need it. 

Cheers,
Doug.

Trung Pham

unread,
Oct 1, 2012, 1:58:31 AM10/1/12
to golan...@googlegroups.com
Wouldn't it be easier to build new tools to assist with testing rather than engineer our way around the lack of tools? Maybe doing so will drive the language adoption. :)

Test Driven Development is a bit of a hassle in Go right now compared to Ruby/Python/Javascript/Java or any other language that has a real mocking library.

gauravk

unread,
Oct 1, 2012, 9:42:41 AM10/1/12
to golan...@googlegroups.com
Sure , You can commission it or write it by yourself what ever tool you need required for Buzzword Driven Development. Apparently most Go users do not feel the need of it.

Kyle Lemons

unread,
Oct 2, 2012, 1:48:25 AM10/2/12
to Trung Pham, golan...@googlegroups.com
On Sun, Sep 30, 2012 at 10:58 PM, Trung Pham <tr...@phamcom.com> wrote:
Wouldn't it be easier to build new tools to assist with testing rather than engineer our way around the lack of tools? Maybe doing so will drive the language adoption. :)

Test Driven Development is a bit of a hassle in Go right now compared to Ruby/Python/Javascript/Java or any other language that has a real mocking library.

I disagree... I find that writing the tests first shows you what interface (both in terms of exported functions and what interfaces) you need, and makes them simple to create on an as-needed basis.
 
On Saturday, March 31, 2012 11:32:26 PM UTC-7, Albert Strasheim wrote:
Hello

On Sunday, April 1, 2012 4:26:33 AM UTC+2, touca...@gmail.com wrote:
So I've fallen in love with dependency injection and Guice, is there anything in/for Go to facilitate dependency injection?

You can do all kinds of dependency injection "stuff" using Go's interfaces and embedding.

I can really recommend looking at what can be achieved with a mix of embedding, other features of interfaces, picking good names for your structs and interfaces, splitting your code over packages, designing your New functions, understanding the issues of untagged struct literals and unexported fields and then putting it all together.

You end up with great code and APIs that can be tested (with or without mocks) and reused in any way you can imagine.

You probably don't need a Guice equivalent. At least not yet.

Cheers

Albert

--
 
 

David Wright

unread,
Oct 2, 2012, 2:03:25 AM10/2/12
to golan...@googlegroups.com
I've never actually used a mocking library for TDD with Java or .NET, and I've done some large projects. Maybe I'm from the stone age, but could you do a little more to sell me on its usefulness? 

David


On Monday, October 1, 2012 1:58:31 AM UTC-4, Trung Pham wrote:

Kyle Lemons

unread,
Oct 2, 2012, 3:53:27 AM10/2/12
to Trung Pham, golang-nuts
Exactly.  If you write the test cases first, and then write the code that will test it, you're forced to see how the code will look in "client" situations.  If you write the test code first, you're much less likely to write test code that depends upon internal state or requires very complicated mock setup in the test.  You tend to factor the important functionality into methods and functions with a clear set of inputs and outputs, and a higher-level set which integrate them that are either obviously correct or which can be tested easily with an integration test.

On Mon, Oct 1, 2012 at 11:31 PM, Trung Pham <tr...@phamcom.com> wrote:

Hmmm. Test Driven Development is all about writing the tests first...

Trung Pham

unread,
Oct 2, 2012, 4:10:51 AM10/2/12
to golan...@googlegroups.com
Look up jmockit or powermock for Java :)

David Wright

unread,
Oct 2, 2012, 4:22:16 AM10/2/12
to golan...@googlegroups.com
"Have you ever heard anyone say that you should never use static or final methods in your code because it makes them impossible to test? Have you ever changed a method from private to protected for the sake of testability? Do you have problems with legacy code or complicated frameworks not designed for unit testing?"

That's not TDD. This is a framework for people trying to write unit tests after the fact. I've had to do that too, but thankfully my answer to these questions is "no".

David

Trung Pham

unread,
Oct 2, 2012, 10:51:11 AM10/2/12
to golan...@googlegroups.com
What you are saying is certainly possible at the component or module level where you have full control over the function interface.

But it gets tricky and complicated at the higher level where you have to integrate all of the modules together. Take the http handler for example, where it only accept HttpRespondeWriter and HttpRequest. How do you inject the dependencies in this case? Maybe you can wrap the http handler in a closure, but that is an unnecessary pain.

Trung Pham

unread,
Oct 2, 2012, 10:56:08 AM10/2/12
to golan...@googlegroups.com
Those two libraries I mentioned are for dealing with static methods, and constructors.
But if you want to have a feel of what mocking is like in general then checkout Mockito. You will like the expressiveness of it and you do not have to go out of your way to get it.

David Wright

unread,
Oct 2, 2012, 2:22:06 PM10/2/12
to golan...@googlegroups.com
But, I don't have any use for this, at all. When I need something like a mock object, I'm better off understanding the problem, taking half a minute, and writing the thing. I'm really not very fond of green eggs and ham.

David

Kyle Lemons

unread,
Oct 2, 2012, 6:45:03 PM10/2/12
to Trung Pham, golan...@googlegroups.com
On Tue, Oct 2, 2012 at 7:51 AM, Trung Pham <tr...@phamcom.com> wrote:
What you are saying is certainly possible at the component or module level where you have full control over the function interface.

But it gets tricky and complicated at the higher level where you have to integrate all of the modules together. Take the http handler for example, where it only accept HttpRespondeWriter and HttpRequest. How do you inject the dependencies in this case? Maybe you can wrap the http handler in a closure, but that is an unnecessary pain.

It turns out that you can pretty easily pass a ResponseRecorder and a constructed Request to the handler you want to test. 

Trung Pham

unread,
Oct 2, 2012, 7:12:17 PM10/2/12
to golan...@googlegroups.com
Can you give an example?
How do I stuff the database connection to the httpRequest interface?

Kyle Lemons

unread,
Oct 2, 2012, 9:23:52 PM10/2/12
to Trung Pham, golan...@googlegroups.com
On Tue, Oct 2, 2012 at 4:12 PM, Trung Pham <tr...@phamcom.com> wrote:
Can you give an example?
How do I stuff the database connection to the httpRequest interface?

There are lots of ways.  Beside the closure method and the wrapper method, you can create a structure that implements ServeHTTP that contains the fields that are "global" and then you just fill that out with your test mock/fake and call the method with the responserecorder.

Jan Mercl

unread,
Feb 15, 2013, 9:26:38 AM2/15/13
to thebrok...@gmail.com, golang-nuts
On Fri, Feb 15, 2013 at 8:53 AM, <thebrok...@gmail.com> wrote:
> Okay, so say you have a function that takes a string and wraps it in parens
> and sends it to fmt.Println. How are you supposed to test that?

A function which transforms a string input and sends it _hard-coded_
to "fmt.Println" doesn't sound to me like most common scenario (modulo
fmt.Printf and friends per se).

Make it return the result or make it write to io.Writer. Then you
would have zero trouble with testing it.

> If you took away the ability to dynamically redefine methods in Ruby (making
> it conceptually one step closer to Go), then you'd just pass your dependency
> as an optional argument:
>
> def print_with_parents(word, putter = Kernel)
> putter.puts "(#{word})"
> end

I don't speak Ruby, but this resembles using the io.Writer suggested above,

> Then of course the test code would send a mock Kernel object.
>
> But since Go doesn't have optional arguments, you're stuck doing kind of
> crazy things. And Go programmers keep saying strange things about this not
> being necessary in Go. I'm baffled.

The cause is maybe, no offense intended, that you're writing Ruby in
Go. That would cause troubles, but Go wouldn't be in such case the
party to blame for them. I'm guessing about this b/c there are people
coding in Go for years which somehow don't run (maybe even never have
run) into such issues, so they must be/probably are doing something
different than what you are doing.

-j

chris dollin

unread,
Feb 15, 2013, 9:36:09 AM2/15/13
to golan...@googlegroups.com
On 15 February 2013 07:53, <thebrok...@gmail.com> wrote:

Independantly of the rest of your post ...

> But since Go doesn't have optional arguments, you're stuck doing kind of
> crazy things.

?

In the (common, possibly commonest) case of one "optional"
argument, you define two functions [1] and have one call the other
with the default value of the optional argument. This may be
inconvenient but it's hardly crazy.

Chris

[1] With different names, "of course".

--
Chris "allusive" Dollin

Nate Finch

unread,
Feb 15, 2013, 3:40:02 PM2/15/13
to golan...@googlegroups.com, thebrok...@gmail.com
Half the problem is, you're testing fmt.Println for some reason. Assume code in the std lib works, and don't bother having your code test it.

Here's a better way to do it:

// formats the string for output
func preformat(s string) string {
    return fmt.Sprintf("(%s)", s)
}

func PrintWIthParens(s string) {
    fmt.Println(preformat(s))


func PreformatTest(t *testing.T) {
    s := "foo"
    expected = "(foo)"
    actual := preformat(s)
    if expected != actual {
        t.Errorf("Actual formatted string '%s' does not match expected value '%s'", actual, expected)
    }
}

No, you're not testing PrintWithParens, but you're testing the meat underneath it.

David Symonds

unread,
Feb 15, 2013, 4:31:23 PM2/15/13
to cl...@electology.org, golan...@googlegroups.com
On Sat, Feb 16, 2013 at 6:27 AM, <cl...@electology.org> wrote:

>> Make it return the result or make it write to io.Writer. Then you would
>> have zero trouble with testing it.
>
>
> 1) How does making it write to io.Writer in any way address the problem? How
> can I replace Writer with a mock to test that io.Writer was called with
> "(foo)"? Since Go isn't a dynamic language, that requires dependency
> injection. I have to be able to substitute a mock in place of the (default)
> io.Writer so I can prove it was called. (Then of course I still have to
> prove that it uses io.Writer in the default case.)

bytes.Buffer satisfies the io.Writer interface, and is used in many
places for these kinds of tests.

David Symonds

unread,
Feb 15, 2013, 4:38:09 PM2/15/13
to thebrok...@gmail.com, golan...@googlegroups.com
On Sat, Feb 16, 2013 at 8:35 AM, <thebrok...@gmail.com> wrote:

> On Friday, February 15, 2013 1:31:23 PM UTC-8, David Symonds wrote:
>>
>> bytes.Buffer satisfies the io.Writer interface, and is used in many places
>> for these kinds of tests.
>
>
> Writing a mock object that satisfies the interface, and allows you to check
> that it was called with the write arguments, is not the problem.
>
> The problem..is how to get the mock object to replace the default object in
> your test.

The answer is to either have a way to inject it at construction time
of the object being tested (and maybe make "nil" mean some sensible
default for regular code), or don't have a "default object" at all and
always pass in an io.Writer. The latter is a perfectly reasonable Go
API.

Jan Mercl

unread,
Feb 15, 2013, 4:49:35 PM2/15/13
to thebrok...@gmail.com, golang-nuts
On Fri, Feb 15, 2013 at 10:35 PM, <thebrok...@gmail.com> wrote:
> On Friday, February 15, 2013 1:31:23 PM UTC-8, David Symonds wrote:
>>
>> bytes.Buffer satisfies the io.Writer interface, and is used in many places
>> for these kinds of tests.
>
>
> Writing a mock object that satisfies the interface, and allows you to check
> that it was called with the write arguments, is not the problem.
>
> The problem..is how to get the mock object to replace the default object in
> your test.

Please explain what is supposed to be that mythical "default object".
There must be some misconception involved in this. There is _no such
thing_ as a default io.Writer. Interfaces do not implement stuff.
Concrete, non interface types do.

-j

Jan Mercl

unread,
Feb 15, 2013, 5:02:54 PM2/15/13
to thebrok...@gmail.com, golang-nuts
On Fri, Feb 15, 2013 at 10:52 PM, <thebrok...@gmail.com> wrote:
> On Friday, February 15, 2013 1:49:35 PM UTC-8, Jan Mercl wrote:
>>
>> Please explain what is supposed to be that mythical "default object".
>
> Everyone else seems to know exactly what I'm talking about, but I'll explain
> again.
>
> By "default" I mean the one that the method normally uses. E.g. you have a
> function that just prints the current date by calling:
>
> fmt.Println(someFunctionThatGetsTheDate())

So, all of your rant has been now reduced to:

Instead of

- testing easily the correctness of what
`someFunctionThatGetsTheDate` returns

you complain about the trouble of the artificial, self inflicted problem of

- testing that fmt.Println(expr)

correctly prints expr?

-j

thebrok...@gmail.com

unread,
Feb 15, 2013, 5:04:40 PM2/15/13
to Jan Mercl, golang-nuts
On Fri, Feb 15, 2013 at 2:02 PM, Jan Mercl <0xj...@gmail.com> wrote:
   - testing that fmt.Println(expr)

correctly prints expr?

You *are not testing* that fmt.Println works. You are testing that it was called with the right data.

Nate Finch

unread,
Feb 15, 2013, 5:08:50 PM2/15/13
to thebrok...@gmail.com, golan...@googlegroups.com

You don't need to test it. It calls two functions that are already tested individually. Trying for 100% code coverage is a fool's errand.

On Feb 15, 2013 4:52 PM, <thebrok...@gmail.com> wrote:
On Friday, February 15, 2013 12:40:02 PM UTC-8, Nate Finch wrote:
No, you're not testing PrintWithParens, but you're testing the meat underneath it.

So then how do I test PrintWithParens? 

--
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...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Ian Lance Taylor

unread,
Feb 15, 2013, 5:09:56 PM2/15/13
to thebrok...@gmail.com, golan...@googlegroups.com
On Fri, Feb 15, 2013 at 1:52 PM, <thebrok...@gmail.com> wrote:
>
> By "default" I mean the one that the method normally uses. E.g. you have a
> function that just prints the current date by calling:
>
> fmt.Println(someFunctionThatGetsTheDate())
>
>
> There, the "default" is fmt.Println. You want to write a test for this
> behavior, but Go isn't a dynamic language, so you can't just redefine
> fmt.Println to be a mock function which records the called values and lets
> you assert that it was passed the output of the date-getting function. So
> you have to use Dependency Injection to replace fmt.Println with a mock that
> implements the same interface.
>
> In a dynamic language like Ruby, this is incredibly simple. E.g. say I have
> this method:
>
> def print_current_time
> Kernel.puts Time.now
> end
>
>
> My test would just be:
>
> describe '#print_current_time' do
> it 'prints the current time' do
> fake_time = mock
> stub(Time).now { fake_time }
> mock(Kernel).puts(fake_time)
> print_current_time
> end
> end
>
>
> This test clearly proves that the method does exactly what we want it to do.
> We *know* that it gets the time from Time.now, and sends that to
> Kernel.puts. This is only possible because the stub() method is able to
> redefine the now() method, and the mock() method is able to redefine
> Kernel.puts. If we couldn't do this, we'd have to use dependency injection.
> Even then, it would still be easier in Ruby because Ruby has default
> arguments.

Yes. This kind of operation is very powerful for some sorts of
testing, and can be very confusing for other uses. Go is not that
sort of language.

One way to test this sort of thing in Go is not to replace
fmt.Println, a complex operation at best. Instead, replace os.Stdout.
It's a bit awkward, but you are the person who decided to write a
function whose API is to print something to os.Stdout. That is not
the kind of thing most functions do, and testing them is doable but
awkward.

E.g.,

package main

import (
"fmt"
"io/ioutil"
"os"
"time"
)

func PrintCurrentTime() {
fmt.Println(time.Now())
}

func main() {
f, err := ioutil.TempFile("", "")
if err != nil {
fmt.Println("ioutil.TempFile: %v\n", err)
os.Exit(1)
}
defer os.Remove(f.Name())
realStdout := os.Stdout

os.Stdout = f
PrintCurrentTime()
os.Stdout = realStdout

_, err = f.Seek(0, os.SEEK_SET)
if err != nil {
fmt.Println("Seek: %v\n", err)
os.Exit(1)
}
b, err := ioutil.ReadAll(f)
if err != nil {
fmt.Println("ReadAll: %v\n", err)
os.Exit(1)
}
if string(b[:10]) != "2013-02-15" {
fmt.Println("FAIL")
} else {
fmt.Println("PASS")
}
}

thebrok...@gmail.com

unread,
Feb 15, 2013, 5:12:50 PM2/15/13
to golang-nuts
On Fri, Feb 15, 2013 at 2:08 PM, Nate Finch <nate....@gmail.com> wrote:

You don't need to test it. It calls two functions that are already tested individually. Trying for 100% code coverage is a fool's errand.

In the Ruby community, we do this all the time, with great success.

You literally seem to be saying people should just be okay not doing unit testing of any code with dependencies.

Jan Mercl

unread,
Feb 15, 2013, 5:20:51 PM2/15/13
to cl...@brokenladder.com, golang-nuts
BTW, your code is dependent on the CPU performing correctly the
machine code given, you should test it according to your methodology.
And don't forget to verify RAM. Any process is dependent on functional
RAM, right?

-j

clay shentrup

unread,
Feb 15, 2013, 5:28:04 PM2/15/13
to Jan Mercl, golang-nuts
On Fri, Feb 15, 2013 at 2:20 PM, Jan Mercl <0xj...@gmail.com> wrote:
BTW, your code is dependent on the CPU performing correctly the machine code given, you should test it according to your methodology.

That is what I am doing and what every other Ruby-using shop (e.g. Twitter, Square) is doing. The hardware is effectively mocked.

--
clay shentrup | 415.295.CLAY

David Symonds

unread,
Feb 15, 2013, 5:29:14 PM2/15/13
to cl...@brokenladder.com, golang-nuts
No, you should be writing code that makes its dependencies clear and
controllable, and then it is easy to test the code against fake/mock
implementations of those dependencies. Instead of writing
func F(s string) { ... }
and just having to know that it happens to write to standard output
(and also thus leading to a function with severely limited use), write
func F(w io.Writer, s string) { ... }
and then just explicitly say "os.Stdout" in the relevant places.

You have brought over a lot of baggage from Ruby. That's
understandable, but baggage nonetheless. Go is not Ruby, just as Ruby
is not Java, and Java is not COBOL. What is natural in one language
may not be natural in another. Have a look through the Go standard
library and see how APIs are designed there.

You care about dependencies of code, and that's good. So do we. The
difference is that Go makes those dependencies explicit, whereas your
Ruby experience is leading you to write code where the dependencies
are implicit or hidden, and thus testing involves monkey patching
those dependencies (or using a framework to do that for you).


Dave.

clay shentrup

unread,
Feb 15, 2013, 5:41:12 PM2/15/13
to David Symonds, golang-nuts
On Fri, Feb 15, 2013 at 2:29 PM, David Symonds <dsym...@golang.org> wrote:
No, you should be writing code that makes its dependencies clear and controllable

This is a bad programming practice, as it makes the code more flexible than it needs to be. If what I need is a function that writes a value to our Redis store, I *do not want/need* to give the caller the flexibility to specify the redis store. This relates to an important principle called YAGNI.

This also produces obvious verbosity. An extra parameter is passed in every occurrence, even if there is *absolutely no need* for the ability to specify an alternate implementation.

You have brought over a lot of baggage from Ruby. That's
understandable, but baggage nonetheless. Go is not Ruby, just as Ruby
is not Java, and Java is not COBOL. What is natural in one language
may not be natural in another.

This is not about language choice. There are patterns and principles that simply work better and produce simpler code, absolutely independent of the language being used. Providing the flexibility for the caller to specify an option that it has absolutely no need for = unnecessary complexity. It just produces unwieldy code. This contradicts Go's general tendency to avoid complexity (e.g. by not having inheritance, not allowing dynamic method definition).

You care about dependencies of code, and that's good. So do we. The
difference is that Go makes those dependencies explicit, whereas your
Ruby experience is leading you to write code where the dependencies
are implicit or hidden, and thus testing involves monkey patching
those dependencies (or using a framework to do that for you).

Monkey patching is fine *for testing*. I agree that in production code, it has led to horrible consequences that will lead any experienced Ruby developer to tear his hair out when having to witness the atrocity of what happens when engineers who don't understand object oriented design patterns go crazy with meta-programming.

So far, I think the solution for this issue might be for Go to have special stubbing/mocking abilities only available in testing. Or for it to simply have optional arguments.

The whole notion that 100% test coverage is too hard is just not acceptable. Every line of code should be a response to a failing test.

Thomas Bushnell, BSG

unread,
Feb 15, 2013, 5:43:53 PM2/15/13
to clay shentrup, David Symonds, golang-nuts
It sounds as if you're programming by mottos. I think such mottos are useful, but they are like Go proverbs. They help to point the way, but following them woodenly doesn't actually help.




--

Ian Lance Taylor

unread,
Feb 15, 2013, 5:47:18 PM2/15/13
to clay shentrup, David Symonds, golang-nuts
On Fri, Feb 15, 2013 at 2:41 PM, clay shentrup <cl...@brokenladder.com> wrote:
>
> So far, I think the solution for this issue might be for Go to have special
> stubbing/mocking abilities only available in testing.

This is very unlikely. Sorry.

> Or for it to simply
> have optional arguments.

I don't see how this helps, given that you want to adhere to YAGNI.

Ian

David Symonds

unread,
Feb 15, 2013, 6:04:19 PM2/15/13
to clay shentrup, golang-nuts
On Sat, Feb 16, 2013 at 9:41 AM, clay shentrup <cl...@brokenladder.com> wrote:

> On Fri, Feb 15, 2013 at 2:29 PM, David Symonds <dsym...@golang.org> wrote:
>>
>> No, you should be writing code that makes its dependencies clear and
>> controllable
>
>
> This is a bad programming practice, as it makes the code more flexible than
> it needs to be. If what I need is a function that writes a value to our
> Redis store, I *do not want/need* to give the caller the flexibility to
> specify the redis store. This relates to an important principle called
> YAGNI.
> http://en.wikipedia.org/wiki/You_aren't_gonna_need_it
>
> This also produces obvious verbosity. An extra parameter is passed in every
> occurrence, even if there is *absolutely no need* for the ability to specify
> an alternate implementation.

You say "more flexible than it needs to be", but then immediately want
a way to make it more flexible for testing. You are treating testing
as some magical thing, when it is only code. This is a common problem
for testing fanatics: not realising that test code is still *code*. If
you have code A and it normally uses B, but for testing you want to
replace B with C, then A should just make that dependency injectable
in its interface, and then you won't be surprised when you discover
the A has some assumptions about B because they are less likely to
happen.

YAGNI is a fine principle, but here you obviously *do* need it: the
test wants the code under test to behave differently, so the code
needs to provide that flexibility.

Seriously: have you read through some of the Go standard library like
I suggested? Things fit together wonderfully, and it does not feel
verbose to do the minimal wiring. You can take compress/gzip.Reader,
give it a net.Conn, and all of a sudden you can decompress directly
from a network connection. All that from the trivial price of having
to pass an io.Reader to compress/gzip.NewReader.

Dan Kortschak

unread,
Feb 15, 2013, 6:24:15 PM2/15/13
to thebrok...@gmail.com, golan...@googlegroups.com
Or you could define an FprintCurrent(io.Writer,...), test that on the appropriate io.Writer and provide PrintCurrent() as a convenience. Just as fmt does.

Nate Finch

unread,
Feb 15, 2013, 11:28:45 PM2/15/13
to golan...@googlegroups.com, clay shentrup
We fell off the mailing list... putting this back on.

I misspoke.  What I meant to say was that monkey patching the dependency doesn't test the method that called the original dependency any more or less than testing the private function that takes an interface.

for example, monkey patching:

func Foo(b []byte) {
    os.StdOut.Write(b)
}

func FooTest() {
    // during test we monkey patch os.StdOut with bytes.Buffer so we can record the output
   // so we're actually testing bytes.Buffer.Write(b), not the original os.StdOut.Write(b)
}

now, example using go interfaces

func Foo(b []byte) {
    foo(os.StdOut, b)
}

func foo(w io.Writer, b []byte) {
    w.Write(b)
}

func FooTest() {
    // during test we pass bytes.Buffer to foo so we can record the output
   // so we're actually testing bytes.Buffer.Write(b), not the original os.StdOut.Write(b)
}

This is what I mean about it being the exact same thing.  Using this private method w/ interface format produces the exact same test that monkey patching would. The ONLY difference is that a coverage tool would say the Foo method is untested... but it's a single line and calls a method that is tested with a type that is tested.... so its behavior is completely tested.

On Fri, Feb 15, 2013 at 9:11 PM, clay shentrup <cl...@brokenladder.com> wrote:
On Fri, Feb 15, 2013 at 5:12 PM, Nate Finch <nate....@gmail.com> wrote:


On Feb 15, 2013 6:48 PM, "clay shentrup" <cl...@brokenladder.com> wrote:
>
> On Fri, Feb 15, 2013 at 3:21 PM, Nate Finch <nate....@gmail.com> wrote:
>>
>> You're assuming the interface parameter is public,  but it doesn't have to be. You can make the public call not have the parameter, default it in that method and have a private implementation take an interface. The private implementation has the interface purely for testing purposes.
>
> But then I'd be testing the private interface, not the public one.

Testing the private function is *exactly* the same as testing the monkey patched public function. *Exactly* the same, except one is visible and obvious, and one is hidden by magic.

No. You *do not* test the monkey patched version of anything. You test that the method under test *called* the monkey patched method with the *right arguments*. That is completely different than testing method B instead of method A, which is what you're talking about.

--
clay shentrup | 415.295.CLAY

Brian Slesinsky

unread,
Feb 16, 2013, 4:36:16 PM2/16/13
to golan...@googlegroups.com, David Symonds, cl...@brokenladder.com

On Friday, February 15, 2013 2:41:12 PM UTC-8, clay shentrup wrote:

This is a bad programming practice, as it makes the code more flexible than it needs to be. If what I need is a function that writes a value to our Redis store, I *do not want/need* to give the caller the flexibility to specify the redis store. This relates to an important principle called YAGNI.

I remember the early days of extreme programming (in Java 4 back then) and the folks who advocated test-first programming and used slogans like "you're not going to need it" (which was targeted at overly abstract object-oriented designs and unneeded functionality) also had it that one benefit of test-first is that it forces you to design a more generally useful API. Also, we didn't have any dependency injection frameworks; it was just a design principle. Heavy reliance on mocks was not all that common, as the only mocks we had were the ones we wrote ourselves. All that came later.

- Brian

Jesse McNelis

unread,
Feb 23, 2013, 10:58:16 PM2/23/13
to thebrok...@gmail.com, golang-nuts
On Sun, Feb 24, 2013 at 1:07 PM, <thebrok...@gmail.com> wrote:
But this is not testing the same thing! There's a subtle difference. The first test actually proves that Foo() passes the right value to os.StdOut.Write. The second has no way to prove that Foo() passes os.StdOut to foo. And I just found out that Go doesn't let you compare equality of two functions, so you can't even prove that the right function is used in the default case. So this is a huge hole in testability for Go.

A test like that would be completely pointless. If the test and the code disagree about what this line should do which one is correct? How could a developer tell which to trust?
If I changed this line of code to instead write to a log file should I just update the tests to test for that function call instead? A unit test isn't going to explain why this function call would be important.

A higher level integration test would give you this information. It would also allow you to actually test your code's interaction with os.Stdout and whether it's properly handling it's errors, using it in a thread safe manner and that all the other code agrees on where to write output too.

Jesse McNelis

unread,
Feb 24, 2013, 12:16:23 AM2/24/13
to thebrok...@gmail.com, golang-nuts
On Sun, Feb 24, 2013 at 3:26 PM, <thebrok...@gmail.com> wrote:
On Saturday, February 23, 2013 7:58:16 PM UTC-8, Jesse McNelis wrote:
If I changed this line of code to instead write to a log file should I just update the tests to test for that function call instead?

Of course! That would be unit testing your code.

No, it's writing the same thing twice without any form of verification that it's correct. That's not testing, that's wasting time.

A unit test isn't going to explain why this function call would be important.

A unit test is going to verify that your code does the right thing. This complaint effectively argues against having unit tests.

Unit tests verify that a unit acts correctly, they aren't concerned with whether the unit interacts with the correct dependencies. The dependencies should be able to be swapped out for mocks or other implementations without making the unit test fail. Foo() in the above code is a wiring function and could be moved outside the unit under test since it's not concerned with the function of the unit but with what dependences it's interacting with.
Since it's only concerned with the dependencies, it's only actually testable in an integration test.


It would also allow you to actually test your code's interaction with os.Stdout and whether it's properly handling it's errors, using it in a thread safe manner and that all the other code agrees on where to write output too.

You don't need an integration test for that. You just stub the call and ensure that it raises the error you want to ensure your code properly handles. E.g. in Ruby:

In a unit test you can test whether the unit interacts correctly with some kind of mock of it's dependencies  But since it's a mock and not the actual dependency it's only a guess at the interaction. Which is why integration tests exist.  

context "when there is an error"
  test_user = mock(User)
  User.stub(:find).and_raise("No such user")
  expect { UserUpdater.update(test_user) }.to raise_error "No such user"
end

It's important to understand the differences between unit tests and integration tests.
 

Jesse McNelis

unread,
Feb 24, 2013, 8:23:40 AM2/24/13
to clay s, golang-nuts
On Sun, Feb 24, 2013 at 6:19 PM, <thebrok...@gmail.com> wrote:

Foo() in the above code is a wiring function and could be moved outside the unit under test

But then how do you test Foo?

There has obviously been some confusion, the "testing in rails" rant was unnecessary  You test Foo() in your integration tests since it having a concrete external dependency means it can't be tested in a unit test. Mocking and stubbing doesn't allow you to test code with dependencies, they just allow you to remove the dependencies so you can test in isolation. 
This is the primary point of dependency injection. You remove concrete dependencies from your code so that you can mock them. Since mocks are fake versions of your actual dependencies you still have to test that the unit really does work with the concrete dependency. This is done in integration tests which also test that injection of the concrete dependency itself was correctly done, which in this case is the code in Foo().

Of course this all appears to be something you already know so I'm not sure where the confusion is.

foo() and the rest of the package is tested by your unit tests. Foo() (note the capital letter) is trivial and is covered by integration tests that test the output of your program contains the output expected to come from Foo() so you know that Foo() is correctly interacting with the concrete dependency os.Stdout. 

If the unit test passes, but the integration test fails then you know that the package is generating the correct result but sending it to the wrong io.Writer. In which case it's a wiring problem and you look at the wiring code i.e Foo().

It's better to test that Foo() uses a os.Stdout in an integration test because you'll probably also want to make sure that other packages are also outputting to the same io.Writer.


--
=====================
http://jessta.id.au

Dougx

unread,
Feb 24, 2013, 11:21:33 PM2/24/13
to golan...@googlegroups.com, thebrok...@gmail.com
For what it's worth, I agree with you.
...but this conversation is getting a tiny bit combative don't you think?

Are you actually looking for a solution now, or just complaining?

If you're looking for a solution, I recommend using var args as optional parameters, this allows for injectable functionality without severely damaging the api. It's a bit of a pathetic solution, but it's the best I've come up with so far.

You could also use a global factory pattern to resolve dependencies if they are injected as 'nil' values to solve your DI requirements, just remember to directly reference the appropriate types using something like this so the types aren't stripped from the build:

reflect.TypeOf((*MyType)(nil)).Elem()


This is certainly something which isn't trivial to do in go, and arguing about "it not being a good idea" isn't productive.

~
Doug.

On Sunday, February 24, 2013 3:19:03 PM UTC+8, thebrok...@gmail.com wrote:
On Saturday, February 23, 2013 9:16:23 PM UTC-8, Jesse McNelis wrote:
On Sun, Feb 24, 2013 at 3:26 PM, <thebrok...@gmail.com> wrote:
On Saturday, February 23, 2013 7:58:16 PM UTC-8, Jesse McNelis wrote:
If I changed this line of code to instead write to a log file should I just update the tests to test for that function call instead?

Of course! That would be unit testing your code.

No, it's writing the same thing twice without any form of verification that it's correct. That's not testing, that's wasting time.

Let me repeat, unit tests and integration tests serves different purposes. Some key points are:

1) Unit tests enable you to easily pinpoint what broke. As opposed to an integration test being more likely to tell me that something broke. E.g. if a controller spec fails and a model spec also fails (particularly a model that seems likely to have been related to that controller) then I can address the model spec first, and it will likely fix the controller test. The more high-level your view of an error is, the more challenging it can be to determine the underlying cause. If all I have are integration specs

2) Unit tests make it feasible to do test permutations. E.g. if I have three methods and they each have 3 different conditional execution paths, then to full exercise those paths would require 27 contexts. Whereas if I just unit test each method, then I have 3+3+3=9 contexts. Much more tractable! Further, I'll get duplicate test setup if e.g. method X and method Y both call method Z, which has several permutations. I can instead test Z's permutations thoroughly, and then simply mock the calls X and Y make to Z. The key is to use this in conjunction with some high level integration tests that, while they don't test every permutation, ensure that these methods are wired up correctly.

3) Unit tests can have dramatic performance benefits. E.g. if there's some intensive query/update job that must happen after a record is updated, I don't want to actually run the query job. I just want to assert that e.g. Resque.enqueue was called with UserReportUpdateJob. I have already tested elsewhere that this job works. I do not want to expend resources making this job run again for no reason.

These are some very fundamental principles in test-driven development, and were some things I learned pretty early when pairing with engineers from Pivotal Labs—one of the thought leaders in TDD. These are important concepts that have dramatic consequences for the efficacy of your testing. You cannot just discard them because they don't ideologically sit right with you. If you use paid time to write 27 combinatorial integration tests when you could have written 9 unit tests and then a handful of integration tests to test the "gluing together" of those independently tested modules, then you're not being responsible with your employer's time. Or your own. You're going to be less successful as an engineer. Pragmatism is important.

Moreover, your argument here is severely flawed. You said, "without any form of verification that it's correct". Well look—every test that isn't a browser-based total integration test is vulnerable to that criticism. If you ever stub out an API (which you certainly should) then you're doing unit testing. Unit testing and integration testing generally aren't black and white. Every integration test is effectively a unit test from the point of view of whatever calls the subsection of the code being tested in that integration test. If you provide an API for a client, then your entire high-level integration spec is just a unit spec, from the point of view of that client.

Abstraction is crucial here.

Unit tests verify that a unit acts correctly, they aren't concerned with whether the unit interacts with the correct dependencies.

You're confused. Unit specs aren't concerned with whether the dependencies work. They take it for granted that the dependencies work. But they absolutely should test that the dependencies are interacted with correctly. If you think you can't write a unit test on anything that has dependencies, then you are going to be blatantly violating TellDon'tAsk/LawOfDemeter, and your code is going to be much less manageable as a result.

You don't just throw decades of wisdom out the window because it offends your gut sensibilities.
 
The dependencies should be able to be swapped out for mocks or other implementations without making the unit test fail.

Only if that's part of the API of the method you're testing. If the job of the method is to take an implementation and pass a message to it, then the test is correct if it merely passes the implementing object to the function and asserts that it received the right message. But if the function under test is supposed to, say, write data to the "createFile" method, then you want to assert that it did that. What you do not want to do is implement the former when what you really need is the latter. You don't want more generality/flexibility than you need just because your language sucks for testability. The right solution is to fix your language.

Foo() in the above code is a wiring function and could be moved outside the unit under test

But then how do you test Foo?

since it's not concerned with the function of the unit but with what dependences it's interacting with.

Everything is a unit, depending on your perspective. You draw a box around any system, it's a unit with an API, from the perspective of the rest of the universe.

Since it's only concerned with the dependencies, it's only actually testable in an integration test.

This statement is just completely wrong. You clearly do not understand what constitutes an integration test vs. a unit test.

Testing that Bob sends Alice a message is a unit test on Bob. Testing that Alice does something based on Bob's message is an integration test. (And from the point of view of the rest of the system, that whole thing is a unit test.) Having a dependency does not make your test an integration test. There are these things called stubbing and mocking that you should learn about if you want to write tests effectively.

In a unit test you can test whether the unit interacts correctly with some kind of mock of it's dependencies  But since it's a mock and not the actual dependency it's only a guess at the interaction. Which is why integration tests exist.

No, it's not a "guess" in any sense. YOU the programmer KNOW what the external dependency is supposed to do. That WHY you can be safe stubbing/mocking it. Because you KNOW what it does and that the expected behavior is already tested. So here is a statement on a very elementary aspect of testing, and you got it exactly backwards.

adam_smith

unread,
May 8, 2013, 3:38:15 AM5/8/13
to golan...@googlegroups.com
Not everything needs to or should be a unit test. There are more ways of testing than unittests. For some things it is easier to test input and output of a program in a script. E.g. The version controll system git is largely tested by large amounts of scripts sending in in inputs to small programs and checking their output. This sort of thing is normal in the unix world. Remember the creators of Go are steep in the unix tradition. Don't expect everything to be done the java way. I know your example is ruby but I think the approach described is left over from the java way of thinking.

junkma...@gmail.com

unread,
Feb 1, 2016, 12:25:17 PM2/1/16
to golang-nuts, cl...@brokenladder.com


On Friday, 15 February 2013 18:04:19 UTC-5, David Symonds wrote:

You say "more flexible than it needs to be", but then immediately want
a way to make it more flexible for testing. You are treating testing
as some magical thing, when it is only code. This is a common problem
for testing fanatics: not realising that test code is still *code*. If
you have code A and it normally uses B, but for testing you want to
replace B with C, then A should just make that dependency injectable
in its interface, and then you won't be surprised when you discover
the A has some assumptions about B because they are less likely to
happen.  

YAGNI is a fine principle, but here you obviously *do* need it: the
test wants the code under test to behave differently, so the code
needs to provide that flexibility.

Seriously: have you read through some of the Go standard library like
I suggested? Things fit together wonderfully, and it does not feel
verbose to do the minimal wiring. You can take compress/gzip.Reader,
give it a net.Conn, and all of a sudden you can decompress directly
from a network connection. All that from the trivial price of having
to pass an io.Reader to compress/gzip.NewReader.

Function parameters should specify options, not dependencies. The ideal function signature should know nothing about it's implementation details. What you're suggesting is to push anything that needs mocking into the function parameters... coupling all the dirty details to the client. What will you do if the function's implementation changes?

Peter Bourgon

unread,
Feb 3, 2016, 6:34:52 PM2/3/16
to junkma...@gmail.com, golang-nuts, cl...@brokenladder.com
Functions probably, and constructors definitely, should specify dependencies.

In Go, dependencies should (probably) take the form of interface
types, pinning behavior rather than implementation.

When a function changes its behavioral requirements, it is natural
that its signature also changes.
Reply all
Reply to author
Forward
0 new messages