smarty / gunit

xUnit-style test fixture adapter for go test
Other
120 stars 11 forks source link

Support complementary libraries by exporting and extending `testingT` interface #17

Closed ghostsquad closed 5 years ago

ghostsquad commented 6 years ago
type Fixture struct {
    t       testingT
    log     *bytes.Buffer
    verbose bool
}

testingT should be exported, to make easy access for other assertion libraries:

In a test function

this.fixture.T
ghostsquad commented 6 years ago

I suppose the alternative to this is something like:

func TestExampleFixture(t *testing.T) {
    f := ExampleFixture{
        t: t,
    }
    gunit.Run(f, t)
}

In a test function

this.t
mdwhatcott commented 6 years ago

I responded to the other issue you opened (which appears to be related). Does that response help?

(We purposefully chose NOT to export the testingT interface, opting to go through the Fixture for all behavior.)

ghostsquad commented 6 years ago

ya, that answered it. Thanks!

megalepozy commented 5 years ago

I may be wrong but I think that this design is also blocking the use of mockgen (https://github.com/golang/mock).

The reason is that you cannot run the following code anywhere: ctrl := gomock.NewController(t) Where t is *testing.T

This is a real bummer... :)

mdwhatcott commented 5 years ago

@megalepozy - I'm new to mockgen (preferring to hand-roll my own mocks). Could you include an snippet of example code that illustrates the way you wish things were?

megalepozy commented 5 years ago

@mdwhatcott well in order to use mockgen you need to run the following code at the start of every test:

ctrl := gomock.NewController(t)
defer ctrl.Finish()

Afterward you create a mock: repoMock := mock_getorganizationmembers.NewMockRepoGateWayer(ctrl)

Which later you describe what you expect it to do: repoMock.EXPECT().GetOrganizationMembers(in.GetOrgURLSignature()).Return(nil, externalError)

Then when running the test, if the mock was not called or got called with wrong values it will raise an error, otherwise it will just return the result set at Return() inside the tested function so the test may continue correctly.

This is just a small part of what it can do, I really like it :)

So basically what I need is just like @ghostsquad needed, access to *testing.T in order to create the controller (ctrl).

btw, though its obvious and its a different testing framework, I'll mention that I used mockgen with goconvey with no problems.

mdwhatcott commented 5 years ago

@megalepozy - After exporting the gunit.testing.T interface I would also have to extend it to include Errorf in order for it to be compatible with the gomock.TestReporter interface (which is what gomock.NewController() requires).

My goal with gunit was to support our testing workflow at smartystreets and we tend to hand-roll our mocks but I'm also not opposed to making gunit play nicely with other complementary tools, such as gomock.

I'm mulling it over. Stay tuned...

megalepozy commented 5 years ago

@mdwhatcott Will do! :)

mdwhatcott commented 5 years ago

@megalepozy - See my recent commits on the mike/export-testingT branch:

https://github.com/smartystreets/gunit/tree/mike/export-testingT

On that branch the *testing.T is exposed via a new method on the fixture, fixture.T(). Would that be suitable for your use case? Feel free to kick the tires and verify that it will work with gomock. If that is acceptable than I'm comfortable merging that branch into master and cutting a new release.

megalepozy commented 5 years ago

It's more then acceptable, it's perfect! :D

I done the following:

func TestCommandFixture(t *testing.T) {
    gunit.Run(new(CommandFixture), t)
}

type CommandFixture struct {
    *gunit.Fixture
    gomockCTRL *gomock.Controller
}

func (cmd *CommandFixture) SetupGoMock() {
    cmd.gomockCTRL = gomock.NewController(cmd.T())
}

// then for each test I only need to create my mock :)
func (cmd *CommandFixture) TestCommand_UserShouldNotBeEmpty() {
    publisherMock := mock_publisher.NewMockPublisher(cmd.gomockCTRL)
// ...
}

Thanks for this awesome package! :)

megalepozy commented 5 years ago

Just in case anyone will wonder about using gomock with gunit I'll add that my previous example is missing defer cmd.gomockCTRL.Finish()

As far as I checked everything work so far for me (I guess cause of the new shiny fixture that is created for every test, thx again @mdwhatcott) so I don't think there is a need to add it but it may be needed to be at each test, or maybe just at a teardown func.