-
Notifications
You must be signed in to change notification settings - Fork 43
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
c439c1b
commit 9fbf2c5
Showing
1 changed file
with
159 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
# How to write tests | ||
|
||
1. You can have a separate function for faktory manager setup that you can call in func main(), for e.g. | ||
|
||
``` go | ||
func faktoryManagerSetup() error { | ||
// create faktory manager | ||
mgr = worker.NewManager() | ||
|
||
// set logger to the app's logger | ||
mgr.Logger = app.Log | ||
|
||
// NewPool creates a new Pool object through which multiple clients | ||
// are managed. | ||
pool, err := faktory.NewPool(5) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
mgr.Pool = pool | ||
|
||
mgr.Use(func(ctx context.Context, job *faktory.Job, next func(ctx context.Context) error) error { | ||
app.Log.Infof("Starting work on job %s of type %s\n", job.Jid, job.Type) | ||
err := next(ctx) | ||
app.Log.Infof("Finished work on job %s with error %v\n", job.Jid, err) | ||
return err | ||
}) | ||
|
||
// use up to N goroutines to execute jobs | ||
mgr.Concurrency = 20 | ||
|
||
// pull jobs from these queues, in this order of precedence | ||
mgr.ProcessStrictPriorityQueues("critical", "default", "bulk") | ||
|
||
// register a job type and the handler | ||
// jobs will go into the "default" queue | ||
mgr.Register("UpdateWiki", UpdateWikiHandler) | ||
|
||
// register another job type | ||
mgr.Register("UpdateReleaseStatus", UpdateReleaseStatusHandler) | ||
|
||
return nil | ||
} | ||
``` | ||
|
||
2. Now, when you are writing a test for a function where you enqueue a faktory job, you can call this function. | ||
|
||
``` go | ||
func TestMain(m *testing.M) { | ||
testSetUp() | ||
faktoryManagerSetup() | ||
exitCode := m.Run() | ||
os.Exit(exitCode) | ||
|
||
``` | ||
3. Table driven testing is a very good way of avoiding duplicate code, and it works really well in this case. Let's take an example: | ||
``` go | ||
var payload []byte | ||
func (suite *FunctionalTestSuite) TestJob_Errors() { | ||
uniqueID := uuid.NewUUID() | ||
testCases := []struct { | ||
name string | ||
hasError bool | ||
expectedError string | ||
jobEnqueued bool | ||
}{ | ||
{ | ||
"Malformed Payload", | ||
true, | ||
"unable to process payload", | ||
false, | ||
}, | ||
{ | ||
"Empty Payload", | ||
true, | ||
"empty payload", | ||
false, | ||
}, | ||
{ | ||
"Empty Metadata", | ||
true, | ||
"empty metadata", | ||
false, | ||
}, | ||
} | ||
|
||
for _, testCase := range testCases { | ||
fn := func() { | ||
payload = []byte("test payload") | ||
pool, _ := faktory.NewPool(5) | ||
perf := worker.NewTestExecutor(pool) | ||
someJob := faktory.NewJob("UpdateWiki", uniqueID, payload) | ||
|
||
// now call the function that actually creates a job in your flow | ||
err = suite.processSomePayload(payload) | ||
|
||
if testCase.jobEnqueued && testCase.hasError { | ||
err = perf.Execute(someJob, func(ctx context.Context, args ...interface{}) error { | ||
return fmt.Errorf(testCase.expectedError) | ||
}) | ||
suite.require.Error(err) | ||
} | ||
|
||
if !testCase.jobEnqueued && testCase.hasError { | ||
err = perf.Execute(someJob, func(ctx context.Context, args ...interface{}) error { | ||
return fmt.Errorf(testCase.expectedError) | ||
}) | ||
suite.require.Error(err) | ||
suite.assert.Contains(err.Error(), testCase.expectedError) | ||
|
||
} else { | ||
err = perf.Execute(someJob, func(ctx context.Context, args ...interface{}) error { | ||
return nil | ||
}) | ||
suite.NoError(err) | ||
} | ||
} | ||
suite.Run(testCase.name, fn) | ||
} | ||
} | ||
``` | ||
Another example for testing the handler response: | ||
``` go | ||
func (suite *FunctionalTestSuite) TestJob_Errors() { | ||
uniqueID := uuid.NewUUID() | ||
testCases := []struct { | ||
name string | ||
hasError bool | ||
jobEnqueued bool | ||
}{ | ||
{ | ||
"Success", | ||
true, | ||
true, | ||
}, | ||
} | ||
|
||
for _, testCase := range testCases { | ||
fn := func() { | ||
pool, _ := faktory.NewPool(5) | ||
perf := worker.NewTestExecutor(pool) | ||
var i interface{} = []string{uniqueID.String(), "payload"} | ||
jobArgs := []interface{}{i} | ||
someJob := faktory.NewJob("UpdateWiki", jobArgs...) | ||
|
||
err = perf.Execute(someJob, UpdateWikiHandler) | ||
suite.require.NotNil(err) | ||
} | ||
|
||
suite.Run(testCase.name, fn) | ||
} | ||
|
||
} | ||
|
||
``` |