Wait, didn't I say that `sum()` sums numbers? And that `is_pred()` returns a
Wait, didn't I say that `sum()` sums numbers? And that `is_pred()` returns a
boolean? How can I sum booleans? What's the expected result of True + True +
boolean. How can I sum booleans? What's the expected result of True + True +
False?
False?
Sadly, this works. Because someone, long time ago, didn't think booleans were
Sadly, this works. Because someone, long time ago, didn't think booleans were
@ -47,11 +47,11 @@ But, for you, you'll now read a line that says "summing a boolean list returns
a number". And that's two different, disparate things that you suddenly have
a number". And that's two different, disparate things that you suddenly have
to keep in mind when reading that line.
to keep in mind when reading that line.
That's why [types are important](/books/things-i-learnt/data-types) are
That's why [types are important](/books/things-i-learnt/data-types). Also,
important. Also, this may sound a bit like [the magical number
this may sound a bit like [the magical number
seven](/books/things-i-learnt/magical-number-seven), 'cause you have to keep
seven](/books/things-i-learnt/magical-number-seven), 'cause you have to keep
two things at your mind at the same thing but, although that's not near seven,
two things at your mind at the same thing but, although that's not near seven,
they are not the same, with opposite (for weird meanings of "opposite", in this
they are not the same, with opposite (for weird meanings of "opposite", in
case) meanings.
this case) meanings.
{{ chapters(prev_chapter_link="/books/things-i-learnt/magical-number-seven", prev_chapter_title="The Magic Number Seven, Plus Or Minus Two", next_chapter_link="/books/things-i-learnt/functional-programming", next_chapter_title="Learn The Basics of Functional Programming") }}
{{ chapters(prev_chapter_link="/books/things-i-learnt/magical-number-seven", prev_chapter_title="The Magic Number Seven, Plus Or Minus Two", next_chapter_link="/books/things-i-learnt/functional-programming", next_chapter_title="Learn The Basics of Functional Programming") }}
@ -13,8 +13,8 @@ tests for the whole compared to tests of single things.
First, I just don't want to into a discussion about what's the "unit in a unit
First, I just don't want to into a discussion about what's the "unit in a unit
test"[^1], so let's take the point that a unit test is a test that tests a
test"[^1], so let's take the point that a unit test is a test that tests a
class/function, not the whole system, which would require data flowing through
class/function, not the whole system from end to end, which would require data
several classes/functions.
flowing through several classes/functions.
There are several libraries/frameworks that actually split this in a way that
There are several libraries/frameworks that actually split this in a way that
you can't test the whole.
you can't test the whole.
@ -22,28 +22,30 @@ you can't test the whole.
those combinations -- and one that I worked with. Due the bean container of
those combinations -- and one that I worked with. Due the bean container of
Java, the extensive use of Beans by Spring and the way Mockito interacts with
Java, the extensive use of Beans by Spring and the way Mockito interacts with
the container, it's pretty easy to write tests that involve only one class:
the container, it's pretty easy to write tests that involve only one class:
You can ask Mockito to mock every dependency injection in one class and mock
You can ask Mockito to mock every dependency injection (so it injects mocked
every injected class, simply using annotations.
beans instead of the real ones) in one class and mock every injected class,
simply using annotations.
And this is cool and all. But the fact that we are making sure each class does
And this is cool and all and makes tests simple and fast. But the fact that we
what it does, it doesn't give a proper view of the whole; you can't see if
are making sure each class does what it should do, it doesn't give a proper
that collection of perfectly tested classes actually solve the problem the
view of the whole; you can't see if that collection of perfectly tested
system is responsible for solving.
classes actually solve the problem the system is responsible for solving.
Once, in C++, I wrote an alarm system
Once, in C++, I wrote an alarm system
[daemon](https://en.wikipedia.org/wiki/Daemon_(computing)) for switches. There
[daemon](https://en.wikipedia.org/wiki/Daemon_(computing)) for switches. There
were three different levels of things the alarm system should do: It could
were three different levels of things the alarm system should do, depending on
only log the message of the incoming error, it could log the error and send a
the incoming message from a service: It could only log the message of the
SNMP message, or it could log the error, send a SNMP message and turn a LED in
incoming error, it could log the error and send a SNMP message, or it could
the front panel on. Because each piece had a well defined functionality, we
log the error, send a SNMP message and turn a LED in the front panel on.
broke the system in three different parts: One for the log, one for the SNMP
Because each piece had a well defined functionality, we broke the system in
and one for the LED. All tested, all pretty. But I still had a nagging
three different parts: One for the log, one for the SNMP and one for the LED.
feeling that something was missing. That's when I wrote a test that would
All tested, all pretty. But I still had a nagging feeling that something was
bring the daemon up, send some alarms and see the results.
missing. That's when I wrote a test that would bring the daemon up, send some
alarms and see the results.
And, although each module was well tested, we still got one things we were
And, although each module was well tested, we still got one things we were
doing it wrong. If we never wrote an integration test, we would never catch
doing it wrong. If we never wrote an integration test, we would never catch
that.
those.
Not only that, but because we wrote a test that interacted with the daemon, we
Not only that, but because we wrote a test that interacted with the daemon, we
could get a better picture of its functionality and the test actually _made
could get a better picture of its functionality and the test actually _made
@ -51,19 +53,23 @@ sense_ -- as in, if you read the unit tests, they seemed disconnected from
what the daemon was expected to do, but the integration tests actually read
what the daemon was expected to do, but the integration tests actually read
like "Here, let me show that we actually did what you asked". And yes, this
like "Here, let me show that we actually did what you asked". And yes, this
was akin to [Gherkin](/books/things-i-learnt/gherkin) tests, although I didn't
was akin to [Gherkin](/books/things-i-learnt/gherkin) tests, although I didn't
know Gherkin at the time.
know Gherkin at the time -- and, better yet, we had tests that proved that we
were following the [spec](/books/things-i-learnt/spec-first).
Personally, I think over time integration tests are more important that unit
Personally, I think over time integration tests become more important than
tests. The reason is that I still have the feeling that unit tests check if
unit tests. The reason is that I personally have the feeling[^2] that unit
the classes/functions have _adherence_ to the underlying_design_ -- Does your
tests check if the classes/functions have _adherence_ to the underlying
view can actually work without the controller? Is the controller using
_design_ -- Does your view can actually work without the controller? Is the
something from the model or using things that should be in the view? -- but
controller using something from the model or using things that should be in
adherence to the design gets better over time -- developers start using the
the view? -- but adherence to the design gets better over time -- developers
layout from previous examples, so they capture the design by osmosis, while
start using the layout from previous examples, so they capture the design by
the big picture starts to get more and more complex, with lots of moving
osmosis, while the big picture starts to get more and more complex, with lots
parts.
of moving parts.
[^1]: There is no "unit" in "unit tests". "Unit test" means the test _is_ a
[^1]: There is no "unit" in "unit tests". "Unit test" means the test _is_ a
unit, indivisible and dependent only on itself.
unit, indivisible and dependent only on itself.
[^2]: Again, it's pure feeling from my experience. I have no data to back that
affirmation up, so take it with a grain of salt.
{{ chapters(prev_chapter_link="/books/things-i-learnt/functional-programming", prev_chapter_title="Learn The Basics of Functional Programming", next_chapter_title="Testing Every Function Creates Dead Code", next_chapter_link="/books/things-i-learnt/tests-dead-code") }}
{{ chapters(prev_chapter_link="/books/things-i-learnt/functional-programming", prev_chapter_title="Learn The Basics of Functional Programming", next_chapter_title="Testing Every Function Creates Dead Code", next_chapter_link="/books/things-i-learnt/tests-dead-code") }}