Vykintas Narmontas (William)
3½yrs Scala specialist
Is unit testing difficult?
No, it is not. You don't even need a testing framework for it.
You don't even need to write the test in a separate file or class.
You just need to exit with code 1. This is enough to fail a Jenkins build and a Makefile!
Why is a unit test useful?
What do you test? when the logic is "complex enough" I know it could be broken 6 months down the line, due to "that one small change" - or that I'd spend time building it with print statements. Example from my own code.
Here, I'll show you the most basic way to unit testing with four languages: Bash, Python, Node.js, Scala, just to prove the point.
These examples are for a very basic piece of code and are intentionally minimalistic, to demonstrate that you needn't use a test framework to get started with - though one will be very necessary when you scale your application.
Here's a bash script inc.sh
with a basic assertion and some main code:
#!/bin/bash
increment() {
echo $(("$1"+1))
}
# If this assertion fails, the whole thing quits
[ 3 -eq $(increment 2) ] || exit 1
# Increment a stream of numbers
while read n; do
increment $n;
done
If we run:
$ seq 1 5 | bash inc.sh
2
3
4
5
6
$ echo $?
0
Exit code is 0. But if we broke the function, and put 2 instead of 1, we get:
$ seq 1 5 | bash inc.sh
$ echo $?
1
This is easy to achieve in any language really. Python assertions:
Broken test in file inc.py
:
def increment(n):
return n + 2
assert increment(2) == 3
$ python inc.py
Traceback (most recent call last):
File "inc.py", line 4, in <module>
assert increment(2) == 3
AssertionError
$ echo $?
1
Comes with assertions built in.
Broken test in file inc.js
:
const assert = require('assert');
function increment(n) {
return n + 2;
}
assert.equal(2, increment(1));
$ node inc.js
assert.js:81
throw new assert.AssertionError({
^
AssertionError: 2 == 3
...
$ echo $?
1
Comes with assert.
def inc(n: Int) = n + 2
assert(inc(1) == 2)
$ scala inc.scala
java.lang.AssertionError: assertion failed
$ echo $?
1
You can get started light with several assertions and work your way up to proper test suites.
To make testing more organised. You get:
Now you have no excuse for not writing at least a few tests in your code.
Not only simple but with functionality like Live Unit Testing (Visual Studio 2017) is also awesome.
This makes me think that I should list a few unit testing frameworks, to make the article more complete.
XUnit! Moq! TestDouble! Karma! Jasmine!
Don't worry. The article is complete enough. ;)
This is a good starting point! I'm not an expert on this topic, but unit testing seems easy when you test "pure" functions. What happens when you have different results for the same input? Or functions that just call functions and you have to start using spies? Would be great if you go deeper in those topics!
Great question!
Exactly! If you want to make your life as easy as possible, you'll have as high a percentage of pure functions as possible. This requires explicit effort.
While you can achieve purity in any language, functional programming languages let you achieve it far more easily.
Personally most side-effecting code I write is also externally facing code, which makes them Integration Tests rather than Unit tests.
I very rarely use spies/mocks and the like. Brittle.
I have a feeling you've got quite a lot more to say about this area than you let on in this post. It'd be quite hard for anyone to gain anything this post , on the one hand they'd have to understand how assertions fit into the bigger picture of unit testing in medium to large scale apps whilst on the other hand they don't have anything but a few simple assertion statements to work with - which they probably already knew in their day to day language
Good comment, your assessment is accurate! I'm however not sure how to express it better though.
I have another article coming on Medium related to building things incrementally though, should be out today or tomorrow.
unit testing is far more complex than writing an assertion statement... this post is pointless :/
What do you have in mind? I'd like to know to improve the post :)
I do use test frameworks extensively and find people have severe resistance to testing because of the learning curve. So this is a simple alternative for the newbie.
What you define as "unit test" in your post are actually mere assertions. They are helpful to ensure the sound state of your internal code but not for documenting and ensuring that your code behaves correctly as expected (as in a unit test). So, I'm not saying that assertions in code are useless, I'm saying that it's not unit testing! moreover an unit test has usually multiple assertions because the goal is to thest a method (the unit) under different scenarios!
hunh. To me this is by far the hardest part of development. I'm not a specialist though. Different strokes for different folks I guess
Why is that the case for you? I'd like to find out so I can solve your problem and make testing better.
I rarely ever have to debug or println any more - just use a test.
Well, for me it's the tooling. Getting everything to work together. The point of your article seems to be not using things like Mocha or what-have-you but I personally would be afraid to test without it. Or rather, I have no idea how I would use your method day-to-day.
This post is a good reminder that you can start off simple and grow into a framework as you need it. Unit testing is ultimately about the tests themselves, and this gives you the straightest path to writing them.
That is exactly my intention. Thanks! :)
That's so awesome! I didn't know about the Bash or Node ones. I've wanted to have some kind of testing for some of my Bash scripts. Thanks for sharing!