
Ask HN: How do I start with test driven development? - pravj
I&#x27;m a student developer, @pravj on GitHub.
I try to follow the best possible development practice when I&#x27;m working like documentation, respecting language&#x27;s style guide etc.<p>But one thing I don&#x27;t like with me is that I never write tests.<p>Why I never followed that aspect is because I always felt that the thing that I&#x27;m writing, sounds totally OK.<p>One another negative point is that I don&#x27;t actually get it that How to do&#x2F;start this and what type of tests I should write for any given project. Maybe this is because I have never done this before.<p>For example recently I wrote a identicons library, Penticons[1]. It generates GitHub contribution flavored identicons. You can read the development story here[2].<p>Now, the thing that stopped me from writing tests was, I thought that ultimately it&#x27;s a image generation library, why this thing needs any tests.<p>I don&#x27;t want to lost my 1 point in the Joel score. Whenever I see a <i>build passing</i> label on a GitHub repository, It makes me crazy.<p>I&#x27;m asking here because I just love HN, I know people will suggest some awesome things here.<p>1. https:&#x2F;&#x2F;github.com&#x2F;penticons&#x2F;penticons.go<p>2. http:&#x2F;&#x2F;pravj.github.io&#x2F;blog&#x2F;penticons-the-hash-game&#x2F;
======
jrochkind1
As far as writing tests... I'm sure you are testing your code manually
yourself already, right? When you make a change, you do something(s) to make
sure your change had the effect you wanted, and your software still worked.
You just do it yourself, manually, and do different things every time of
course.

Take those things, write automated tests to test them. Run the automated tests
instead of testing manually, every time you can. Especially when making
changes don't run the software yourself to see if your changes did what you
wanted, write a test to do it and run that. The first time one of your tests
catches a bug that you never would have expected, you'll be hooked.

"Test-Driven Development" actually refers to (almost) always writing the tests
_before_ you write the code they test. Not everyone subscribes to this, at
least universally. I wouldn't worry about that for now, I think if you just
start writing automated tests every time you would have been manually testing,
you'll be on the path and things will fall into place.

~~~
spenuke
This is the point. You are most likely already testing your code (logging,
printing, or the like).

I learned how to write tests and I was sold on the value of TDD only after I
was in the middle of writing a non-trivial, multi-module client/server app.
Right now, you think "I don't need to write tests for my penticons library,
because I know it works." That's understandable. But as soon as you start
incorporating it into other projects, or you extend it with other projects,
having tests will make the process so much simpler.

Think about it this way: computing is essentially a way to repeatedly do
things really quickly. I could take a pencil and a paper and write the numbers
from 1-100 without too much trouble. But when that number is over 1000, or if
instead of simply writing the number you perform some tedious formula, then
you start to yearn for something like a `for` loop control structure.

The same with testing. Once you have a bunch of moving pieces, and every
change you make you find yourself diving into the repl for 10 minutes doing
the same thing over, and over, and over... you will actively WANT to know how
to test.

So don't sweat it. Learn it if you want. Sooner or later, you're going to
_need_ and _want_ to know how to write good tests, simply to save yourself the
hassle.

------
ollysb
I can't recommend the discussion between Kent Beck, David Hansson and Martin
Fowler enough. They look at how and where it should be used and in particular
discuss their approach to mocking which I feel is an often misunderstood tool.

Part 1 -
[https://www.youtube.com/watch?v=z9quxZsLcfo](https://www.youtube.com/watch?v=z9quxZsLcfo)

Part 2 -
[https://www.youtube.com/watch?v=JoTB2mcjU7w](https://www.youtube.com/watch?v=JoTB2mcjU7w)

Part 3 -
[https://www.youtube.com/watch?v=YNw4baDz6WA](https://www.youtube.com/watch?v=YNw4baDz6WA)

Part 4/5 -
[https://www.youtube.com/watch?v=gWD6REVeKW4](https://www.youtube.com/watch?v=gWD6REVeKW4)

~~~
swanson
This was a great discussion, but I think it is not appropriate for a beginner
just getting into TDD. There were so many nuances in this series that I don't
think it would be helpful as an introductory resource.

------
defenestration
I can give you some pointers. 1) A good discussion about Unit Testing on
Hacker News. Is most unit testing a waste or not?
[https://news.ycombinator.com/item?id=7353767](https://news.ycombinator.com/item?id=7353767)

2) A story about unit testing at Airbnb: [http://nerds.airbnb.com/testing-at-
airbnb/](http://nerds.airbnb.com/testing-at-airbnb/)

3) Practical tips for test driven development:
[http://soundsoftware.ac.uk/unit-testing-why-
bother/](http://soundsoftware.ac.uk/unit-testing-why-bother/)

~~~
pravj
Reading the Airbnb story now, thanks for the links.

~~~
defenestration
Sure, you're welcome. If you would like to grasp where you can go with test
driven development and continuous integration, check out this article: 'How
Etsy Deploys More Than 50 Times a Day":
[http://www.infoq.com/news/2014/03/etsy-deploy-50-times-a-
day](http://www.infoq.com/news/2014/03/etsy-deploy-50-times-a-day) (Btw. I
won't say that deploying 50 times a day is a best practice in all cases)

------
mkolodny
My favorite resource for learning how to test your code is
[http://getpython3.com/diveintopython3/unit-
testing.html](http://getpython3.com/diveintopython3/unit-testing.html)

Once you start testing your code, it's addictive. Testing gives you
confidence.

\- By forcing you to detail your requirements, writing tests helps you make
sure that you're building the right thing.

\- Testing lets you refactor your code with confidence -- if your old tests
still pass after you refactor, your new version works the same way as your old
version.

\- Testing makes your code much (MUCH!) more maintainable. As long as your old
tests still pass, you can be confident that the new code you wrote didn't
break any of your old code.

~~~
pravj
Yeah, addictive it is.

I remember last year contributing[1] to a 2048 python game, where the
maintainer committed[2] test suite lengthy than my commit and He was doing it
like a charm.

I think I should start from that very repository as I know it very well
already.

1\.
[https://github.com/bfontaine/term2048/commits?author=pravj](https://github.com/bfontaine/term2048/commits?author=pravj)

2\.
[https://github.com/bfontaine/term2048/commit/6f9a46283c2cc0a...](https://github.com/bfontaine/term2048/commit/6f9a46283c2cc0a2bf105f3e899e3f127d62610b)

~~~
abecedarius
That looks good. For counterpoint, here is my 2048 including tests for just
the tricky bit:
[https://github.com/darius/sturm/blob/master/2048.py](https://github.com/darius/sturm/blob/master/2048.py)

I have Emacs set up to run them on a keypress without even having to save the
file; you can create and run these tests even quicker than trying things out
in a REPL, and unlike the REPL they persist to be rerun after the next change.

If you've been feeling like testing is too much work, one angle is to reduce
the amount of work it'll take to start.

------
swanson
Start watching James Shore's "Let's Play: TDD" videos [1]. Yes, it is in Java
and about making a basic desktop app for finance tracking - but that doesn't
matter. I'm cutting out paradox of choice and just telling you to start here
:)

This is a great introduction to the basics of TDD, is appropriate for
beginners, shows trial and error (not edited/rehearsed 'final versions'). It
is very digestible (15 min per episode) and free to watch on YouTube. It will
seem tedious at times, but just commit to watching the first couple episodes
and stick with it.

Destroy All Software, "Is TDD Dead" Hangouts, other more specific books, etc
are all _amazing_ resources - but they are not a good place for a beginner to
start. Once you have a basic understanding and have personally run into some
of the tricky situations (mocks/stubs, testing at system boundaries, slow test
suites, etc) these are invaluable, but until then just file them away to
revisit later.

[1]: [http://www.jamesshore.com/Blog/Lets-Play/Lets-Play-Test-
Driv...](http://www.jamesshore.com/Blog/Lets-Play/Lets-Play-Test-Driven-
Development.html)

~~~
jdlshore
Thanks for the plug. :-) I also have a JavaScript TDD screencast at
[http://www.letscodejavascript.com](http://www.letscodejavascript.com).
Different technologies and challenges, same concept.

------
nethopp3r
I've found the Craftsman series by Uncle Bob[1] to be very helpful in showing
how to do not only TDD, but also pair programming. Before that I would
complete tutorials and exercises, but was never able to effectively use it in
actual projects. The Craftsman series shows the steps of using TDD in both
easy and tricky situations, such as socket code, and enabled me to become much
more comfortable with the process.

[1]
[http://www.objectmentor.com/resources/publishedArticles.html](http://www.objectmentor.com/resources/publishedArticles.html)

~~~
daxelrod
I was just about to post this! Craftsman was the the thing that made me
actually grok TDD.

------
michaelmcmillan
I got into it by watching DAS (destroyallsoftware.com) by Gary Bernhardt
(creator of the WAT presentation), it has truly shaped me into a better
developer. Not only will you learn how to practice TDD, but so much more:
refactoring, unix tools, OO-principles ... I could go on forever, it's really
a great series.

------
IlPeach
Hi, currently writing a book on the subject and I'm doing a bit of research
myself.

There are two aspects of testing that you need to discern: the development and
the project management point of view. The first regards what and how to test
things. This can be achieved by any developer and is moderately easy with the
right help and mentoring. The second instead is the most difficult: trying to
force tests in a non-test-focused environment, where the business does not
understand the meaning and/or the value of testing can be poisonous to us and
the business itself. In other words there must be an effort in both
directions. I can keep talking about these two points, but I'll skip them for
now unless you're interested.

Regardless of the current environment you're in, and taking for granted that
the second part is - if not fully, at least partially satisfied, let's have a
look at how to start with TDD: the major problem you're facing is that TDD
does not define "what to test". That's why BDD was introduced, to fill in the
gaps that TDD has.

Still BDD is somewhat lacking depth and proactive understanding from the
project level on how much should be spent on unit tests, how much on
functional and acceptance tests. On this note, Google has defined the ACC,
which helps you define the testing plan for your application; I think it's
totally worth from both a developer and business perspective to dig a bit more
into that, especially if you want to get into testing properly.

If you still fail to see why tests are important, let's put it down this way,
using James Whittaker's words: "although it is true that quality cannot be
tested in, it's equally evident that without testing is impossible to develop
anything of quality".

my 2 cents

~~~
collyw
"Hi, currently writing a book on the subject and I'm doing a bit of research
myself."

"trying to force tests in a non-test-focused environment, where the business
does not understand the meaning and/or the value of testing can be poisonous
to us and the business itself"

Sorry to be a bit negative, bit it sound like you have a conclusion that you
want to reach before you have done your research. That's not really how
research should work. Research should be done and conclusions reached
afterwards.

------
logn
TDD is a subset of automated testing as a whole. You'll find proponents of
testing who might not actually like TDD. It's more of an opinion about the
best approach. Anyhow TDD is essentially writing the APIs, interfaces, and
function signatures first, then writing tests, then implementing things under
the hood, then getting tests to pass.

Automated testing (unit or integration tests) is an extension of taking those
little one-off things we do during development to make sure things work, and
formalizing them to be a permanent part of the code base. Some people go
further then and try to add tests for every feature or (gasp) every single
line and sub-line of code.

It's easy to get carried away with testing. And some people have valid
arguments against testing. But it's nothing too hard or unapproachable. The
point really is that everyone does testing already, but not everyone keeps all
their tests and makes them nice.

~~~
Bahamut
Case in point: I'm big on testing (I have pushed testing hard at three
companies I have been at), but I dislike TDD strongly. I have often found that
I am not sure how I would like to design components until I start
implementing, and TDD is too rigid for arriving at an optimal implementation.
I prefer to figure out the implementation, then write a thorough set of tests.

------
AndrewDucker
The reason you _need_ tests is so that (a) when you change some code in the
future it doesn't break any of your functionality without you knowing about it
and (b) if someone else changes you code it doesn't break any of your
functionality without you knowing about it.

If you don't believe that you need unit tests, you won't write them - so step
one is persuading yourself that they're useful. So try to remember a time when
you broke your code in an unexpected way, and then try to work out what kind
of unit test would have helped avoid that.

------
jezclaremurugan
Well the question looks more like a why instead of a how.. answering the how
is simple, if you are starting on a new project (as you seem to be), start
with unit tests for all functions, for anything that talks to DBs/external
APIs use mocks.

Answering the why,

scenario 0 - it forces you to have functions that do one thing and one thing
well. Unit testing mostly helps people keep functions small and focused.

scenario 1 - assume you are working on a fun app without tests. Everything is
fine and the app works great. After some time you decide to add a new feature
X, and you realize you need to modify an existing function to achieve that..
you modify that, and the new feature X works fine, but two days later you will
realize that an old feature Y is broken.

scenario 2 - scenario 1 but with collaborators instead of yourself revisiting
the app.

scenario 3 - people use unit tests to understand code - while reading/working
on other people's code. Unit tests also serve as excellent examples on how to
call/use something, which params to pass etc.

There are a lot more reasons esp for large projects, and you never know when a
small one off project grows into something big and critical so its recommended
to always start with unit tests as adding them later is usually 10x more work
as it would require refactoring etc.

------
jordanpg
Testing and certainly TDD usually fall by the wayside because it takes too
long. At least that is the perception. I see two keys to keep tests
lightweight, fast, and desirable.

First, you should choose testing and mocking libraries and learn them
completely and totally. They are usually not that complicated. Read all the
docs and memorize all the neat things they can do. Most libraries have a best
practices guide. Read it and follow it. The point of this is to make sure that
you can write tests as quickly as you can write trivial if/then statements.

Second, keep your tests as simple as possible while still testing behavior. Do
not verify that every variable is set or if every method is called, or the
right thing is passed everywhere. The tests should read like documentation: it
should do x, it should do y. If you find the process of writing tests arduous
or difficult to maintain, you're overcomplicating your tests (and probably
your code, too).

In a word: lightweight.

------
hugs
In general, don't worry (too much) about tests in the beginning of a project
until it's likely you'll have more than one user (aka yourself) and/or paying
customers. If you have neither users nor customers, don't feel too guilty
about your lack of tests. In many cases, it's more important to make something
useful enough that makes an investment in more testing later worthwhile.
Later, when you _do_ have users and customers, you will want your tests to
discover regressions before your users do.

However, the longer you wait, the higher the risk that you'll discover your
code is not easily testable... which will require lots of refactoring to make
testable. And that refactoring is made harder by the lack of tests...

In the meantime, if you're truly stuck, write down a list of how you're
currently manually testing your code and write down edge and corner cases
you're worried about.

(disclosure: I make testing tools for a living.)

------
MattyMc
In August of this year I walked into a job interview for an entry-level'ish
Rails dev position at a start-up. Already having a great job in education, I
made clear that I was weak in testing and needed a plan to patch things up.
I'm now very confident with testing using MiniTest. Here're my 2 cents:

\- Build something super easy (<4 hours), using Test-Driven Development. The
example I used was a URL shortener.

\- Rebuild one of your existing apps using Test-Driven Development. If you're
wondering where to get started, watch videos titled "creating a simple app
using ____ and TDD", or even consider calling the Rails hotline.

\- Get someone to look at your test code for you. I learned a ton from this, I
can't even begin.

\- Use MiniTest. RSpec is amazing, but I found MiniTest to be more transparent
as to what was actually happening.

\- Check out the codeschool and codeacademy tutorials. Very helpful.

Best of luck. It's a very difficult topic, one that I really struggled with.

------
kureimoru
I would like to point out that TDD isn't really about tests, it's about design
of your program. It forces you from the very beginning to deal with really
important questions: how do one use a piece of your program? Is it easy, clear
and simple? Can it be tested? What do you expect from the program? Is your
program or component overcomplicated?

Design your programs from top to bottom fleshing out details as you go. Deal
with one abstraction at a time. And when you're finished you can throw away
non-critical tests so that they don't outlive their purpose.

Do remember that tests are code too and that they have to be maintained and
that they can become a part of technical debt. Do not use TDD for prototypes
when you really don't know how or why implement your program. Create a
prototype, explore possibilities, throw the prototype away and write a
production version with TDD.

~~~
collyw
A lot of the time (certainly in my work) the requirements are incomplete /
vague enough, that it is easier just to build a prototype and work from there.
As such tests will just require two or three times as much code, and there is
a fair likely hood that they will be thrown way afterwards.

I know this does not fit waterfall or TTD / agile methodology, but I am
certain that there is a very large percentage of IT workers that have to work
this way.

------
briantopping
TDD without refactoring is like sex without orgasm. Okay, maybe it's not that
bad.. ;)

Seriously, the most fun I ever had with TDD was when using a language that my
IDE had great refactoring tools for. Just write all your code inside a test to
start with, don't bother with production anything. The test becomes a little
like a command line program, launches immediately from the IDE and you can
iterate super quickly. Your output is whether the test (with the test data)
passes or fails. I'd pick the test framework by whatever the IDE liked best.
Pursue solutions that viscerally satisfy until you know better.

Once you have a test working like that, do "Extract Method" followed
immediately by "Move Method". The destination of the move is the production
class. With two menu selections, you have a perfectly testable interface,
called perfectly by the test. A good extract refactoring always proposes
parameters for the method and lets you order and rename them. It will also
recognize extractions that can't work, like when two results are generated by
the selected code. In that case, extract more than one method and move all the
methods to the production code.

Want to add more code? Do the same thing again and again and again, each time
as a new test.

When you are done, you'll have production classes that are the composite of
the extractions and all the tests that once contained inline code (but now
contain method calls to the production code).

At some point, you will ask "how can I improve my tests?" The answer is easy:
Code coverage tools. You should shoot for > 80% of your production code having
test coverage. Some say more, few say less. Make some rules for yourself about
things you don't bother testing, like getters and setters, use the 20% leeway
so you aren't flogging yourself. Keep having fun, don't make a death march out
of testing every last line of code.

This habit becomes really fun. You'll start telling your friends. Nirvana will
ensue.

~~~
sklarsa
What IDE did you use? Can this workflow work in Visual Studio using NUnit?

~~~
mrbrandonking
ReSharper is an add-on component for Visual Studio that is (IMO) the best
refactoring tool available for any IDE. ReSharper includes an NUnit-based test
runner, too.

JetBrains is the company that makes ReSharper. I also use AppCode (their
alternative to Xcode) in a way that's similar to how I use ReSharper. I do
most of my iOS development in Xcode but load the project in AppCode before
committing so I can take advantage of its superior code inspection and
refactorings.

------
SEJeff
So TDD is a difficult thing to get into from the beginning. The more
experienced you are as a developer the easier it will be to write tests. The
thing that is great about TDD is that it forces you to write discrete and
modular code as it tends to be easier to test that way.

This week, one of my coworkers described being new to TDD like being new to
vim. There is a horribly steep learning curve but once you "get it" it becomes
second nature. The real win of TDD, especially for open source, is that when
the projects start to get bigger and harder to manually test you can merge PRs
with a bit more confidence that you're not breaking things. I can speak with a
bit of experience here as an OSS co-maintainer of two pretty large (>500
unique contributors) projects, graphite, and salt.

------
jermo
TDD takes time and is hard to get right at first. I'm sure you will find the
usual tutorials so I would rather recommend this blog post:
[https://www.stevefenton.co.uk/Content/Blog/Date/201305/Blog/...](https://www.stevefenton.co.uk/Content/Blog/Date/201305/Blog/My-
Unit-Testing-Epiphany/)

and Ian Cooper's talk "TDD, where did it all go wrong":
[https://vimeo.com/68375232](https://vimeo.com/68375232)

In a nutshell: test your high level API and not your implementation, minimize
your usage of mocking.

------
junto
For .Net developers I can recommend the combination of local dev machine
continuous testing using NCrunch, manual runs using the unit test runner in
Resharper and then the NUnit test runner in TeamCity.

TeamCity is a gatekeeper. Builds that fail unit testing don't get
automatically deployed. Locally NCrunch keeps you updated on what is broken
without you having to think about running your tests, since it runs them in
the background for you. Resharper unit test runner helps you run and debug
specific tests or groups of tests.

I work on a large application with many other developers and this flow works
well for us.

------
m52go
James Shore's TDDJS series is supposed to be excellent:
[http://www.letscodejavascript.com/](http://www.letscodejavascript.com/)

------
vpeters25
I usually start with an "it works" test that calls each method with expected
inputs and asserts an expected result. The expected result most of the time is
that it didn't throw an exception. I found that such tests usually cover most
of each method and are pretty effective at detecting regressions.

When I'm fixing a bug, I first create a test that fails when reproducing the
conditions that cause it, then I make necessary changes until that test
passes.

------
grandalf
Thinking about testing can help with good overall design. Consider:

\- How can I build a small, testable unit that can be combined with other
small, testable units?

\- How can I design a small, testable unit with a stable interface?

\- How can I test this small testable unit in isolation and in various
production/deployment scenarios?

Choosing the right building blocks to focus on meshes well with testing
thinking b/c it lends itself to a bottom-up philosophy.

------
mrbrandonking
The best introduction to TDD that I've seen is Jon Reid's video tutorial
here...

[http://qualitycoding.org/objective-c-
tdd/](http://qualitycoding.org/objective-c-tdd/)

Even though he's demonstrating TDD with Objective-C, I've recommended this
video to .NET developers and they've still had an "Aha!" moment when Jon
explains the "TDD Waltz".

------
aaronem
> ultimately it's a image generation library, why this thing needs any tests

So you can be confident that it generates correct images, even three years
from now when you've mostly forgotten about it but you dip back in just to add
a quick feature without thinking about it very much -- or, for that matter,
when someone submits a pull request, and you want to make sure it doesn't
break anything.

------
rmetzler
One very easy thing to test for is wether your SVG creating code actually
returns valid XML/SVG or not.

Then you might want to make some of these magic values configurable so users
can create different sizes or different color schemes and some of them might
be dependent. Unfortunately, I doubt that this refactoring is done without
mistakes. Maybe you should write some tests before and then refactor.

------
mattxxx
TDD in what language? It's all about workflow. So if you're using java, you
should get familiar with mvn and the junit lib. If you're using NodeJS, then
you need to do something like mocha and grunt.

TDD gives you insane test coverage, but your process becomes: 1) Write a
failing test 2) Write some code 3) Run test 4) Repeat 2 & 3 until test works,
then go back to 1.

------
veihan
Long time ago I also didn't write tests. Now this software causes me the most
problems. For start you shouldn't focus on testing with any methodology like
TDD, BDD, etc., just ignore it. Better read about Right-BICEP, this going to
help you shift way of thinking. Anyway after some hellish struggling you
should be able always to think out tests before code.

------
crdoconnor
>Now, the thing that stopped me from writing tests was, I thought that
ultimately it's a image generation library, why this thing needs any tests.

I'm not sure this one does. It's a very simple library and there's no bugs in
the issue tracker.

I would write a test for the first bug you encounter, though.

Or, if you start writing a more complex method on a new feature, start TDD'ing
that.

------
ranko
There were two things that helped me get started: pairing with a more
experienced developer who did TDD, and reading Growing Object-Oriented
Software, Guided by Tests by Steve Freeman and Nat Pryce. You might not have
the luxury of the first, but the second is pretty accessible, even if you
don't use the particular tools that the authors demonstrate.

------
hluska
I thought TDD seemed like a waste until I wanted to really figure out Rails
and went through mhartl's Rails tutorial. By the end of the book, I realized
that TDD had automated all the silly manual tests I did, and actually saved me
time. I was kind of shocked, though thats what I get for thinking I actually
knew an answer...:)

------
raverbashing
Really, you start by starting.

First grab a testing framework for your language, if it's not built-in.
Something that runs the tests in your project once you run a command.

Following that, add a test to a function in your project. You can start with
an easy one. Try that and see what works, try covering corner cases, etc

Then you can go for actual TDD once you write new code.

------
seanwilson
Tests for Penticons sounds straightforward to be honest. After saving some
example images generated from a set of inputs, write some code that checks
those inputs produce those images. Imagemagick has image comparison commands
that can help . I did something similar when optimising a gaussian blur filter
and found it useful.

------
vinceguidry
I personally got started with Gary Bernhardt's excellent Destroy All Software
screencasts. I started with the third season for his series on untested code,
and got the other four soon after.

[https://www.destroyallsoftware.com](https://www.destroyallsoftware.com)

------
laurencei
Personally I love Uncle Bob's videos. He has some great TDD theory and work
throughs - it is how I got started:
[https://cleancoders.com/](https://cleancoders.com/)

Specifically episodes 6 and 7. But if you have time - I recommend most of the
videos

------
pypetey
Writing tests is like writing articles. You just have to start writing and at
some point you will get better.

Writing tests will change your coding style and way of thinking which is
great. You might read some articles about testing for your language of choice.

Just start :)

------
tejohnso
When you're writing your procedures, you have to think about what you want
them to do. What small unit of work each procedure should perform. That's the
best time to write the tests for the procedure, because it will help you to
think of edge cases that you might otherwise miss, and it will confirm that
the procedure does what you expect before you move onto the next. It's also
the easiest time to write the test for the procedure, because you haven't yet
committed to any particular level of complexity or dependency structure. If
you write tests first, your code will always be testable. If you attempt to
show up the next day and start writing tests, you may find that the person who
wrote the code yesterday wrote some pretty untestable code. Another benefit to
having the tests is that they will continue to pay off as you modify the code
weeks and months later, always confirming that you haven't broken anything.

Like most other learning endeavours, I found that the best approach was to
start small. Try something simple like a fizz-buzz test. You'll probably have
more trouble setting up and writing the tests than writing the code under
test. That's okay. Like any other learning process, it takes time to get used
to the new language and behaviour that is required to become fluent in writing
testable code. Make sure that every time you save your working code, your
tests run and you can see the result so that you get immediate feedback. And
make sure to always work in as small a unit of work as seems comfortable.

Here are some example test function names for fizzbuzz

1\. itPrintsFizzForMultiplesOfThree() 2\. itPrintsBuzzForMultiplesOfFive()

These tests might be too broad in scope. Where is it getting the numbers that
it's checking for multiples? What does "print" mean? How are the tests going
to confirm what was printed?

1\. itReturnsTrueForMultiplesOfThree() 2\. itReturnsTrueForMultiplesOfFive()
3\. itReturnsEitherFizzOrBuzzOrTheNumber() 4\. itSendsTheResultToOutput()

These tests are against simpler methods and are easier to write but the
tradeoff is that they make the code under test too fine grained at times. Can
you have too many tests? I don't think that's likely in practice, not if
they're true unit tests and extremely quick to execute. But some would
disagree when they see a five method fizzbuzz class rather than a class with
one "doTheWholeThing" method. You have to find what works for you. When you
return to your code a day or two later, do the tests immediately make sense?
If not, they're probably too complicated. Start small, get a feel for the
shift in mindset, grow from there.

------
christiangenco
Here's the thing with TDD: until you work on a project that's either

a) contributed to by a lot of developers that aren't familiar with the source
code,

b) so large that you're scared of making any substantial changes because the
last time you did that another piece broke and it took forever to figure out
it was actually broken and another forever to figure out how to get both
pieces working together and in the process you half-broke this other piece and
GAH maybe I should just rewrite the entire thing, or:

c) mission-critical, where a piece not doing what it's supposed to means lost
lives or money,

then TDD is a net waste of time. Much like learning git, you'll be fighting an
uphill battle with your mind at every stumbling block ("ugh this is so
complicated - why am I learning this again? Doesn't putting my source code in
Dropbox solve all of these problems already?") until you have an actual, real,
legitimate use for the solution ("oh right, I'm learning git because using
Dropbox to collaborate means 'conflicted copy' city").

Tests don't have to be complicated. They don't have to use the next new shiny
framework, they don't have to have a smart lookup system that auto-runs files
that are checked in and sends you an email if you push bad code; tests are
just if statements, and they're mostly the if statements that _you 're already
running through your mind when you program_. Here's a hopefully not too
contrived example:

When you wrote commit 4a069[1], how did you know the code you wrote actually
_did_ anything? From my quick understanding of reading this over, it looks
like you changed `padding` and `size` from constants (5 and 30 respectively)
to variables set somewhere else (in `utils.go`). If you made all these changes
at once, then re-ran whatever code you use to make a penticon, the expected
behavior is that you'd see the exact same thing as before (test#1).

But wait, were you even editing the same file you ran? Let's double `Padding`
and `Size` in `utils.go` and make sure it changes the image (test#2). Alright
cool, it does. But wait, the padding looks way too big - is it twice what it
needs to be? Let's try `Padding = 1` and `Padding = 0` and make sure that
looks how I expect it to (test#3, test#4). Awesome - that's perfect.

Does the size work too? I wonder if this would break if the `Size=0` (test#5).
Oh shoot, what if _both_ the size and padding were 0 (test#6). OH SHOOT WHAT
IF THEY WERE NEGATIVE? (test#7).

\---

All of that to illustrate: the difference between what you're (probably) doing
right now and TDD is that in TDD you write down each test as you're testing
it. At the end of adding those two variables you'd have a second file of 7 if
statements that make sure that changing the size and padding works like it's
supposed to.

Unfortunately, `penticons.go` is a horrible project to bring TDD into your
workflow because 1) it's tiny and can probably fit in your head all at once so
you'll know immediately anyway if something breaks, and 2) testing images is
hard. It looks like a lot of your other public projects are equally as TDD-
unnecessary.

What you _could_ do is generate a bunch of references images (like a 1x1px
empty image for when the padding=1 and Size=0), then write a script that runs
the code that should generate the same image and make sure they match bit-for-
bit. Again, though: until you're feeling the pain that having the piece of
mind that no other part of your program was just broken by what you did, you
don't need to add TDD to your workflow.

1\.
[https://github.com/penticons/penticons.go/commit/4a069619545...](https://github.com/penticons/penticons.go/commit/4a06961954530ece6a8c451feee7b1027a3f5e30)

~~~
oldmanjay
This is almost like saying until you've been injured in a car accident there's
no reason to wear your seat belt.

~~~
christiangenco
I'd argue that it's closer analogous to wearing a regular seat belt until you
start driving in situations where the benefits of wearing a five-point harness
outweigh the cons of reduced driving mobility.

------
rvalue
isnt TDD dead already ?

Just write unit and integration tests

~~~
_random_
Still feeds the trainers and book-writes and as such is "the-only-correct-way-
to-write-correct-software".

------
buildops
Have you tried Typemock? It helps you get started with unit testing and offers
a free version

------
jasenmh
I'd recommend learning a new language that has a strong TDD community. I
started testing and TDD by adding unit tests to an existing C++ project and
didn't really get the point. I recently picked up Ruby and the course I took
taught RSpec alongside Ruby. It made so much more sense. Plus, learn another
language.

------
ninjakeyboard
You start with a test (that fails).

------
bbcbasic
TDD requires you write the test first, then the code later. At an extreme you
would write a test for a minimal piece of functionality, then do the minimal
amount of coding to get the test to pass and then repeat. I.e. you would write
no production code that is not covered by a test.

This takes a lot of discipline and I have never done it a t work but it is fun
to try at home to see what the extreme case is like. I don't do this at work
because I have no control over 99.99% of the production code and how loosely
coupled it is for testing. (In C#, but in Ruby you can get away with it due to
duck typing).

TDD forces you to write code that is testable. So you never should end up
thinking 'oh shit I need to expose that private member variable to make this
class testable'.

Anyway just try it and then as you get stuck read up on how to do TDD. I am
always an advocate of try before you learn (makes the learning easier).

