I believe that one of the reasons people struggle with writing tests is a lack of a systematic approach.
Personally, when I write tests, I don’t like the feeling of getting stuck and not knowing what’s the next step to take.
That’s why over the years I developed a system which is basically a series of questions I ask myself each time I write new tests.
This system is documented in the “HiRez TDD Guide” which I give each student of my Angular Testing Basics course.
In this post I’d like to share one short principle from that TDD guide.
Where should I start from?
OK, you’re staring at a blank spec file…
some setup code...
}) // OK, what should I do now?});
The spec file is looking right back at ya and begging:
“OH DEAR GOD! WOULD YOU WRITE SOMETHING ALREADY???”
But you’re stuck, because there are too many options to choose from:
“where should I start from?”
“How much should I test?”
“Should I configure a spy?”
“Should I write an expectation here?”
“Should I just delete this spec file and watch ‘Serious Dev Talk’ instead?“
Ready, Set, ACTION!
Relax buddy, I got your back… 😉
The easiest thing to do, is to start from identifying the “action” you need to trigger of course.
It’s the thing that causes other stuff to happen (I know, real academic material we got here…)
You see, every (micro) test should always test one action that you subject under test either triggers or reacts to.
“But Shai, that’s too general, there are tons of “Actions” we could test for…”
Not so fast there cowboy… the good news is that:
There are only three “action types”
Yep, there are only 3 types of actions you can test for —
- Initializing the subject under test (Initialization)
- Calling a method or a function (invocation)
- Triggering an event
This means that you can reduce your mental load into asking yourself the following question:
“What is the action type I’m currently interested in testing?”
Once you identify the action type you need, the next easiest step to take is to trigger that action in your test.
The three action types… in action!
This is what you should ask yourself in the beginning of each new test:
1. “Am I testing what happens after the subject under test is being initialized?”
This action is called — Initialization
Depending on the “subject under test”, the action, for example could be creating a new class by injecting it
serviceUnderTest = TestBed.get(MyService)
Or compiling the component and by that creating the DOM -
componentFixtureUnderTest = TestBed.createComponent()
This is the initialization action.
You could also ask yourself:
2. “Am I testing what happens after I call one of the subject under test’s methods?
This action is called ”Calling a method” (thanks, captain obvious…) and it’s pretty self explanatory —
That’s the action right there.
If it’s neither initialization or method calling, it must be:
3. “Am I testing how the subject under test reacts after an event is triggered?
This action is called triggering an event.
And it could be dispatching a DOM event like a mouse click, or even emitting a notification on an Observable (by using a subject).
And that’s it, this is all you need to ask yourself at this point in order to move forward, pretty neat huh?
Once you trigger the action, the next best thing is to figure out the possible use cases for that action, but I’ll write about that in a future post.
- Always start by asking: “What’s the action type I’m testing”
- There are only 3 action types — INIT, METHOD / FUNCTION and EVENT
- The first step of your test should be to trigger the action,
that’s the easiest thing you can start from.
So.. what do you think? do you agree that there are only 3 types of actions? do you have any other insights?
I’d love to hear your thoughts in the comments below 👇
In the meantime, happy testing!
If you wanna learn more, I’m opening up a free workshop soon about Angular Testing, you can register at TestAngular.com to be notified when it starts.