2. Content
1. Definition of Unit Test and benefits of writing unit
tests.
2. TDD introduction, methodology and benefits.
3. Effective use of TDD.
4. Applying TDD to our project.
3. What is a “Unit Test”?
A "unit" is a piece of code, method or function that
has a single responsibility.
A "unit test" is a piece of code that invokes another
piece of code and checks the correctness of some
assumptions. If the assumptions turn out to be
wrong, the unit test has failed.
4. Unit Test Benefits
compare to Integration Test
Integration Test Unit Test
• A integration test group 2 or more • A unit test tests only a single unit in
dependent units and test to see if they isolation
work properly together.
• Integration tests are harder to write, • Unit tests are easy to implement, they
easy to fail if they have an external works with fake dependencies(Stub and
dependency which is unavailable for Mock), run and give results quickly
some reason
• Integration tests are hard to maintain. • Unit tests are super easy to maintain
When a test fail, we have to debug to because they cover a small piece of
see what is our problem. functionality.
• Integration tests help to document • Unit tests help to design and document
main features of our application. our code.
5. TDD Introduction
Traditional approach: many people feel that the best time
to write unit tests for software is after the software has
been written. It sounds reasonable but there is code we
can’t write unit test without modifying. There’re many
cases we have to modify our code to make it unit-testable,
which may lead to other problems, slow down our
schedule…
Test Driven Development: Write tests first, use unit tests
drive the design and document our code. With TDD, we
begin with the end in mind.
6. TDD Methodology
The general TDD cycle goes as follows:
1. Write a failing test first to prove code or functionality is
missing. The test will fail because we haven't implemented
that functionality yet.
2. Make the test pass by writing production code that meets
the expectations of your test. At that moment, we just need
to pass the test, the code should be as simple as possible.
3. Refactor your code when the test passes, make it more
readable, remove code duplication...
By writing and passing unit tests, we add more
functionality, a bit at a time until all requirements are
fulfilled.
7. TDD Benefits
Writing unit tests actively will make most of our code are
covered by unit tests. That will raise the confidence in the
code.
Help to create quality code, better designs, document our
code....Write test first help us really understand the design
of code. Instead of writing code to do something, we're
starting by outlining all conditions we may have, all
expected output.
Speed up our development in a long run. We done when
we finish the last line of code, we don't need to spend
much time debugging, we don't need to manually check if
our new features break the old code, existing features.
9. Effective use of TDD
TDD brings us a lot of benefits. TDD = Too
However, there is no silver bullet, TDD Damn
doesn’t ensure project success. On the Difficult
other hand, TDD is a double-edges
sword and if it is done incorrectly, it
will waste our time, lower our code
quality.
In order to apply TDD effectively, we
have to know exactly what to test and
how to write a good unit test.
10. What to test?
Any classes and components that contain logical
code, e.g. if…else, for, switch…case, any calculation
or interaction with other components, calls to
external methods.
Logical code could be found on server side or client
size. We have to test them all.
11. Unit testing on server side
Repository Layer: verify the persistence and retrieval
implementations produce the correct results.
Business Logic Layer: focus on verifying the business rules
and their interactions with Repository Layer. The tests do
not actually store data in the repository but use a fake
repository and verify the business services layers uses it
correctly.
Web Layer: we create unit test for request handlers, verify
their interactions with business service, e.g., "Are they
called correctly?", "Are the view models returned
correctly?"
12. Unit testing on client side
The basic rule is to test anything a designer would not
change. We would not test that a specific font value
was set or a specific background color of an element
was used.
We test the property values of a view model, whether
a calculation is correct, an event is triggered, a DOM
element are modified correctly, a AJAX callback
function has been called or not...
13. How to write a good unit test?
A good unit test must be simple, trustworthy, maintainable and
readable.
Naming unit test:
MethodUnderTest_Scenario_ExpectedBehavior()
ex: AuthorizeUser_WrongUserName_ReturnFalse()
Avoid logic in tests: having logic will increase chances of having
bugs in unit tests. avoid "if, switch, for..." to generate input, try
to hard code.
Testing only one thing, avoid testing multiple aspects: each unit
test should generally take one action and make one assertion. if
our tests contain more than a single assert and the first assert
fails, it will throw exception and the second assert never run.
14. How to write a good unit test?
Avoid duplication: put duplicated code in TestCleanup and
TestInitialize method for maintainable reason.
Don't test things that obviously work.
Enforce test isolation: a test should always run in its little
world, isolated from its dependencies. We do not want to
think our subject under test is broken because one of its
dependencies broke and caused the subject under test to
fail. If We test like this, We might spend a lot of time
tracking down bugs in the wrong place. Testing how things
operate together is the domain of integration testing, not
unit testing.
15. Applying TDD to our project
Server side: We still have not implemented business
services yet, so, most of code reside in action’s
Execute methods. In those methods, we don’t care
about what business services do or what they return,
we only need to test, if we have to, whether they
have been called correctly or not.
16. Applying TDD to our project
On client side, we have 3 layers that contain logic:
View Model: verify all behaviors(CopyUser, LoadUser…),
computed properties
Repository: verify whether the call to server has been
made and callback function has been triggered correctly or
not.
Presenter: most of our UI logic resides here. We should
write unit test to verify circumstances, e.g. whether a
button is enabled/disabled, a list is empty, selected item
changed, user click Save button.
17. How to write unit-testable code?
Just need to remember: “objects do not create other objects on
which they rely to do their work. Instead, they get the objects that
they need from an outside source”.
We have 4 common ways to achieve this: Constructor, Setter and
Getter, Interface, Service Locator(factory pattern, local factory
method).
All necessary techniques can be found in:
The Art of Unit Testing – Manning
Test-driven Development By Example - Addison Wesley
Dependency Injection in .NET - Manning