Hi Kyle,
I was resistant to "complicating things" by adding a Rendering Context, but the more I think about it, this sounds like the way to go. In fact, an RC could be useful for the production code, as it could be a struct that caches state.
So let's see if I got this. I need to setup a RenderingContext and a FakeRenderingContext, which higher level functionality would make use of (rc, fakerc). Then I need an interface to satisfy the type checker when passing an rc in. Code that was calling the gl package directly would instead need to use the rc.
type Errorable interface {
Error()
}
type Error map[gl.ErrorCode]bool // too many things called Error! :-)
// Get Error
func GetError(rc Errorable) Error {
err := Error{}
// "glGetError should always be called in a loop, until it returns GL_NO_ERROR"
for code := rc.Error(); code != gl.NoError; code = rc.Error() {
err[code] = true
}
if len(err) > 0 {
return err
}
return nil
}
type FakeRenderingContext struct {
}
func (rc FakeRenderingContext) Error() ErrorCode {
return gl.NoError // or something
}
In reality, I imagine GetError() above would receive the RC indirectly through some context of its own. Then I can use the FakeRenderingContext to stub out the low-level functionality. This struct could contain some state, if I wanted to return a different error each time, or count how many times GetError() called Error(). In this case the behaviour should be that Error() is called "number of errors + 1" times.
I'm not sure exactly what you mean by "assertion-style frameworks" and why they are best to avoid?
I've heard of two styles of testing. One with mocks that would verify the "messages", eg. Error() is called twice. The other way I've heard of is to assert state, such as that the return value is nil.
But I wouldn't consider myself an accomplished Tester. I think the main trouble I'll have is how to scale this up, whether to have lots of different FakeRCs and small interfaces, or to fake out the entire GL stack and try to customize that with delegation. That, and just how to write good tests that test the right things!
Thanks for pointing me in the right direction, and for getting me thinking.
Nathan.
On 21 August 2012 16:02, Kyle Lemons
<kev...@google.com> wrote:
Even though I wrote one for giggles, I actually haven't found much use for mock generators myself. They seem to me like they're often used with assertion-style frameworks, and this mailing list long ago taught me why not to use those :). In any case, you would need to create an interface that mimicked a type (you cannot "stub" out a package in Go) and that interface could either be backed by the underlying package or by your testing mock. It looks like gl.Error() is a package-level function; one approach would be to have a Context-style interface and object on which you call such methods, so that they aren't rooted in the package.