Pre/Post condition patterns in tests.
This is “Rubber duck debugging” article.
So there are common assumptions that we do on daily basis and we think about them not like assumptions but rather as given.
As good engineers must be skeptical about any assumption. So lets dig into one of those.
I just want to discuss readability of the code. Just you know:
“Code is read more often than it is written” →link
So despite of the pattern, code will be executed in the same order. I will use JS syntax in examples, but (pre/post)conditions have the same naming as jUnit so I hope more people will understand me.
So lets do IT!
We will start with less used patterns.
I wonder if some one really use them, if so please leave a comment bellow.
Preconditions + Test + Postconditions
describe(() => {
beforeAll(() => {});
beforeEach(() => {}); it('test one', () => {
// test logic
});
it('test two', () => {
// test logic
}); afterEach(() => {});
afterAll(() => {});
});
Pros:
Code is written in same order as it would be executed.
Cons:
Preconditions is splitted, really unusable to see postcondition you must scrooool to to bottom of file.
Conclusion:
Unreadable. Just unreadable, despite picturing real code execution, splitting pre/post conditions are bad idea. What meant to be together must stick together.
(Before/After)All + (Before/After)Each + Tests
describe(() => {
beforeAll(() => {});
afterAll(() => {}); beforeEach(() => {});
afterEach(() => {}); it('test one', () => {
// test logic
});
it('test two', () => {
// test logic
});
});
Pros:
(Before/After)All are sticking together. Logic behind it that if you start some service in BeforeAll you must shutdown it in AfterAll. In that case you can easily see all code of BeforeAll and AfterAll at one place.
Cons:
Order of execution of precondition is not the same as they execution. And in case of massive (Before/After)All block, the (Before/After)Each can be out of your visual scope, so you need to scroll down.
Before(All/Each) + After(All/Each) + Tests
describe(() => {
beforeAll(() => {});
beforeEach(() => {}); afterEach(() => {});
afterAll(() => {}); it('test one', () => {
// test logic
});
it('test two', () => {
// test logic
});
});
Pros:
(Pre/Post)conditions is written the same way as they will be executed. It is give you clear understanding in witch exact order services will be spinnen-up and shutdown afterwards.
Cons:
BeforeAll and AfterAll are split apart with (Before/After)Each block. So you may need to scrol at some point.
A little bias about execution order of pre/post conditions. Despite the fact the order is correct. (Before/After)All will be executed only once and (Before/After)Each will be executed as much as you have tests in file.
Conclusion
After I wrote this article I’m leaning more (Before/After)All + (Before/After)Each + Tests approach.