Also, the shadowing of t in t.Run is intentional. You should not try to work around it. There's no risk of confusion either because you will always use the right one in the right place.
As that applies to software, a mock is a fully-fledged implementation of an interface, but not the implementation you use under normal use. For example, a mock might be an in-memory database where you normally use a persisted database. Not the real implementation, but does not try to deceive – it is equally functional.
Mockery appears to be an assertion library that, bizarrely, moves the assertions into interface implementation. What purpose does it serve? You are going to end up testing implementation details by using that, which is a horrible road to go down.
I wouldn't describe swapping a persisted DB for an in-memory DB mocking personally.
Consider a function with a key/value database dependency:
type DB interface {
Get(key string) string
Set(key string, value string)
}
func ContrivedFunction(db DB) string {
db.Set("key", "value")
return db.Get("key")
}
And let's test it using mockery: func TestContrivedFunction(t *testing.T) {
db := mocks.NewDB(t)
if ContrivedFunction(db) != "value" {
t.Error("unexpected result")
}
}
Code looks reasonable enough, but then... Epic failure. This should work, at least it should if `db` is a mock. But it does not work. `db` deceived us. Clearly not a mock in any sense of the word.But, okay. It is still something. We will play its game:
func TestContrivedFunction(t *testing.T) {
db := mocks.NewDB(t)
db.Mock.On("Set", "key", "value").Return()
db.Mock.On("Get", "key").Return("value")
if ContrivedFunction(db) != "value" {
t.Error("unexpected result")
}
}
Wonderful. We're back in business. Tests are passing and everything is sunshine and rainbows.But now, the contrived project manager just called and, for contrived reasons, would like to change the organization of record keys:
func ContrivedFunction(db DB) string {
db.Set("ns:key", "value")
return db.Get("ns:key")
}
Ah, fuck! The test just broke again. But it shouldn't have. The utility of ContrivedFunction – that which is under test – hasn't changed one bit. The DB implementation should have been able to handle this just fine. The DB implementation used in production handles this just fine. This mockery tool is fundamentally broken.But not only is it broken, it doesn't seem to serve a purpose. Why would you even use it?
I'd add using testing.T.Cleanup for tearing down the testcontainer (or use a TestMain and a deferred if the container is slow and concurrency-safe.)
- I prefer state-based TDD as opposed to interaction-based (see https://martinfowler.com/articles/mocksArentStubs.html).
- I've used both testcontainers and dockertest, and from my experience dockertest is more robust.
- The capital T for the outer argument comes across as being hypercorrect. Why would one consider the shadowing of this argument bad?
It's perfectly ok to take what you like from them and leave the things you don't.
Is something that has 7 useful things and 3 things you disagree with merited to be buried from public view because of the 3 things you personally disagree with?
I've never really understood this perspective.