Skip to content

Instantly share code, notes, and snippets.

@mottaquikarim
Created January 3, 2021 06:01
Show Gist options
  • Save mottaquikarim/00ac5999767be02d3987bdadac62f26e to your computer and use it in GitHub Desktop.
Save mottaquikarim/00ac5999767be02d3987bdadac62f26e to your computer and use it in GitHub Desktop.

TL;DR: use $(eval ARGS=${ARGS} [some additional arg]) within a make target to build custom argument sequences for commands wrapped by make targets - like make test

I expound further on the usecase and methodology below 👇


I like to wrap common tasks, such as running unit tests, around a make target.

This way, I can minimize the length of the command I need to run (ie: make test vs go test ./... -race -coverprofile=c.out)

However, as a project grows, it becomes necessary or just preferable to support a variety of permutations of the above.

(Note: I am not advocating that one ought to use make targets in this manner, just that if this route is chosen, there are patterns available to simplify things a bit).

For the sake of go, here are a few potential tests I'd like to be able to run:

Run tests w/race conditions check

https://gist.github.com/f3802a97982641511c2070f93abffec0

Run tests in "short" mode

https://gist.github.com/a7905053f7086a236669b52c097e5078

Run tests w/verbose results in terminal

https://gist.github.com/40410f2e77a4502177048a8faa974a66

Run tests for a specific package

https://gist.github.com/bdb900a76c28473726633eaf0488e28e

Run a specific test func in a specific package

https://gist.github.com/d953eb548136140a6ab3fc406f91cba9

A better way

Of course, the main issue that comes up here is: what if we wanted to mix and match some of these opts? (For instance, we might want to run tests on a specific package with verbose test output with race condition checks enabled.)

Again, assuming we'd like to reuse the make test interface, our make target can get really messy really quickly:

https://gist.github.com/59f8d4212e52f74f969e038c748c8305

In this example, we only support two use cases, run all tests in a single package and run all tests in all packages in current working directory. Even so, as you can probably see, it is easy to miss stuff (for instance, package tests have the verbose flag) and repetition can start to seep in (note the -coverprofile arg in both conditions).

An alternative (and personally, preferable approach might be):

https://gist.github.com/d986520acbe1a8263a561e0f22a802b4

In this approach, we use $(eval ARGS=${ARGS} [append an arg] to build the actual args for our go test invocation based on make target args.

What's nice about this approach is we can choose to make certain things default vs non default by leveraging make's ifdef and ifndef (if not defined) conditionals.

The last line is the actual test invocation and if we wanted to, we could always echo ${ARGS} right before for debugging purposes, etc.

I really like this approach and have started using it in a lot of my makefile target patterns where I leverage make test for dev-ing or ci related tasks. While I've walked through a golang based usecase, this pattern can be used for more or less any make target usage (though personally, I really only use this for running tests during dev/ci).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment