Start test names with “should” (2020)
paperless.blog
paperless.blog
“Should” to me is too weak.
No, it’s not just “should”. It does. And if it doesn’t then either the implementation is broken, or the test is bad.
“Should” has connotations for me of something that we want but which we don’t require.
Therefore, I don’t use the word “should” in my test names.
Instead of “should have length 256”, I say “has length 256”.
> MUST This word, or the terms "REQUIRED" or "SHALL", mean that the definition is an absolute requirement of the specification.
>SHOULD This word, or the adjective "RECOMMENDED", mean that there may exist valid reasons in particular circumstances to ignore a particular item, but the full implications must be understood and carefully weighed before choosing a different course.
Join the world of needing to make the FAA happy and your vocabulary will change to incorporate shall, will, must, and others in a more discerning manner.
"this test tests that" input has length 256
Since the prefix would be equal for all the tests only the last part becomes the name.
Now I consider that style boilerplate, and just write “X shall hold.”
If it’s at the start of every test it’s completely redundant.
The valuable advice here is that a test function should be named to reflect what it is testing rather that the name of the function it calls.
Depending on the test library you use, there’s already in built stuff for this.
The prefix is not the point, but it might help to write better names for tests:
- can handle negative input
- cannot handle zero
- should return a http error code
Might be better than:
- test calcultate negative
- test calcultate zero
- test handler http code
- handles_negative_input
- handles_zero
- returns_http_error_code
- negative_input
- zero_input
- bad_request
When you run the "bad_request" test, you should get an error code, but that's on the assert already.
It was a nice way to learn implicit rules in an applied manner.
(Sorry for the nonstandard punctuation, but it's necessary here.)
Will also admit that I was a big DSL fan back in the ruby heyday. Works great if it's only you on the project but requiring a whole team to be DSL domain experts for something like testing is asking quite a lot.
What if a test is testing that something shouldn’t happen? Apostrophes aren’t even legal function names in most languages. (/s)
> If the only output of a failing test is just a binary value like “FAIL”, that test is only giving one bit of information to the developer.
Well that aaaand
> A good test framework will also print the test name and a call stack.
Ok so more than one bit of information, it literally tells you the line number and filename of the failed test so you can go look at it. But yeah maybe bad developer didn’t put any comments in the test and the code isn’t obvious but sure they’re gonna name the test using a magic template.
> For example, they could point out that “should replace children when updating instance”
So in Go we would have:
func TestShouldReplaceChildrenWhenUpdatingInstance(t *testing.T) { … }
Argh this nonsense cargo culting just does my head in and I should go to sleep.https://onsi.github.io/ginkgo/#adding-specs-to-a-suite
It’s actually worse than that example suggests. Stuff like Expect(“type safety”).ShouldBe(GreaterThan(13)) throws runtime errors.
The semantics of parallel test runs weren’t defined anywhere the last time I checked.
Anyway, you’ll be thinking back fondly to the days of TestShouldReplaceChildrenWhenUpdatingInstance because now you need to write nested function calls like:
Context(“instances”, func …)
Describe(“that are being updated”, …)
Expect(“should replace children”, …)
And to invoke that from the command line, you need to write a regex against whatever undocumented and unprinted string it internally concatenates together to uniquely describe the test.
Also, they dump color codes to stdout without checking that they are writing to a terminal, so there will be line noise all over whatever automated test logs you produce, or if you pipe stdout to a file.
It’s crazy isn’t it? People inventing a DSL to describe tests which you could just see by reading the friggin’ source code. It’s like ORMs for tests. Let’s create an abstraction (test DSL) over another abstraction (a friggin’ programming language) so now we have to understand two languages.
So of course the solution is to write tests for the tests. Which will require coverage analysis. To make sure the devs take it seriously, I f the tests on the tests don’t get 100% test coverage of the tests then the dice rolling app won’t build.
Because you can never be too sure.
it 'should increment the counter' do ...
but now the active voice preferred it 'increments the counter' do ...
I much prefer the latter.- Don't name your test "test [function name]"
- Don't lean on comments to explain the test
I agree it would be annoying to be forced into strict naming, but let's not ignore the author's point here.
it 'should not do something' def test_increment():
assert ...UnitOfWork_StateUnderTest_ExpectedBehavior
https://osherove.com/blog/2005/4/3/naming-standards-for-unit...
PS: by the way, “unit under test” is probably a better name than “unit of work”
>You usually have at least a number of tests for each method you are testing, and you are usually testing a number of methods in one test fixture (since you usually have a test fixture per class tested). This leads to the requirement that your test should also reflect the name of the method begin tested, not only the requirements from it.
> A unit of work is a use case in the system that startes with a public method and ends up with one of three types of results (...)
I use the same naming as well, and I really like it.
using var uow = UnitOfWorkContainer.Begin();
await SomeDep.Save(foo); // internally uses the uow's transaction
await SomeOtherDep.Save(foo2);
uow.Complete();In that case, it's required that tests be prefixed with "test"[1].
[0] https://developer.apple.com/documentation/xctest
[1] https://developer.apple.com/documentation/xctest/defining_te...
For instance in python both unittest and pytest expect test cases to be prefixed by “test”, but unittest allows overriding this via the loader’s testMethodPrefix (https://docs.python.org/3/library/unittest.html#unittest.Tes...) and pytest via the naming conventions configuration (https://docs.pytest.org/en/7.1.x/example/pythoncollection.ht...).
I agree, as long as there is 1 methot to test per file containing the tests. Otherwise, I put the tested method name first (if it's a unit test) and adhere to the pattern [method]_[should]_[condition]_[result], e.g. Divide_Int_ByZero_FailsWithException()
It works nicely with Jest as you can nest test suites indefinitely, so each GIVEN statement goes in a nested describe block, but it is verbose.
I was thinking when I first saw this I thought this depends on what testing framework you’re using.
Basically, what this is saying is to follow the conventions of the testing framework?
This information could go into the test function name, but you can be much more verbose in the freeform text. And it's guaranteed to move along with the assertion during a refactor, unlike comments that can get separated from the code.
It should be easy to write out requirments in simple terms.
Or better yet, don’t start it with should:
test(‘replaces children when updating instance’)