Testing
=======

Testing is an important part of software development. Whether we are aware of it or not, we conduct testing continuously.
For example, when we write a class in PHP, we may debug it step by step or simply use echo or die statements to verify
that implementation works according to our initial plan. In case of web application we're entering some test data in forms
to ensure the page interacts with us as expected. The testing process could be automated so that each time when we need
to verify something, we just need to call up the code that do it for us. The code that verifies that result matches what
we've planned is called test and the process of its creation and further execution is known as automated testing, which
is the main topic of testing chapters.


Developing with tests
------------------

Test-Driven Development (TDD) and Behavior-Driven Development (BDD) are approaches of developing
software by describing behavior of a piece of code or the whole feature as a set of scenarios or tests before
writing actual code and only then creating the implementation that allows these tests to pass verifying that intended
behavior is achieved.

The process of developing a feature is the following:

- Create a new test that describes a feature to be implemented.
- Run new test and make sure it fails. It is expected since there's no implementation yet.
- Write simple code to make the new test pass.
- Run all tests and make sure they all pass.
- Improve code and make sure tests are still OK.

After it's done the process is repeated again for another feature or improvement. If existing feature is to be changed,
tests should be changed as well.

> **Tip**: If you feel that you are losing time doing a lot of small and simple iterations, try covering more by your
> test scenario so you do more before executing tests again. If you're debugging too much, try doing the opposite.

The reason to create tests before doing any implemenation is that it allows you to focus on what do we want to achieve
and fully dive into "how to do it" afterwards. Usually it leads to better abstractions and easier test maintenance when
it comes to feature adjustments in for of less coupled components.

So to sum up pros of such approach are the following:

- Keeps you focused on one thing at a time so both planning and implementation are getting better.
- Results in test-covering more features in greater detail i.e. if tests are OK most probably nothing's broken.

In the long term it usually gives you a good time-saving effect.

> **Tip**: If you want to know more about the principles for gathering software requirements and modeling the subject
> matter it's good to learn [Domain Driven Development (DDD)](https://en.wikipedia.org/wiki/Domain-driven_design).

When and how to test
------------------

While test first approach described above makes sense for long term and relatively complex projects it could be overkill
for simpler ones. There are some indicators of when it's appropriate:

- Project is already large and complex.
- Project requirements are starting to get complex. Project grows constantly.
- Project is meant to be long term.
- The cost of the failure is too high.

There's nothing wrong in creating tests covering behavior of existing implementation.

- Project is a legacy one to be gradually renewed.
- You've got a project to work on and it has no tests.

In some cases any form of automated testing could be overkill:

- Project is simple and isn't getting any complex.
- It's one-time project that's going to be expired.

Still if you have time it's good to automate testing in these cases as well.

Further reading
-------------

- Test Driven Development: By Example / Kent Beck. ISBN: 0321146530.
