2. What is a UNIT OF WORK?
• A unit of work is the sum of actions that take place between the invocation of a
public method in the system and a single noticeable end result by a test of
that system. A noticeable end result can be observed without looking at the
internal state of the system and only through its public APIs and behavior
3. What is a unit test?
• A unit test is an automated piece of code that invokes the unit of work being
tested, and then checks some assumptions about a single end result of that
unit. A unit test is almost always written using a unit testing framework. It can be
written easily and runs quickly. It’s trustworthy, readable, and maintainable.
It’s consistent in its results as long as production code hasn’t changed.
4. PROPERTIES OF A GOOD UNIT TEST
• It should be automated and repeatable.
• It should be easy to implement.
• It should be relevant tomorrow.
• Anyone should be able to run it at the push of a button.
• It should run quickly.
• It should be consistent in its results (it always returns the same result if you don’t
change anything between runs).
• It should have full control of the unit under test.
• It should be fully isolated (runs independently of other tests).
• When it fails, it should be easy to detect what was expected and determine how to
pinpoint the problem.
5. INTEGRATION TESTS
• Integration testing is testing a unit of work without having full control over all of
it and using one or more of its real dependencies, such as time, network,
database, threads, random number generators, and so on
• Difference between Unit Test & Integration Test
• An integration test uses real dependencies; unit tests isolate the unit of work from its
dependencies so that they’re easily consistent in their results and can easily control and
simulate any aspect of the unit’s behaviour.
7. Techniques of TDD
• Write a failing test to prove code or functionality is missing from the end product
• The test will fail to compile
• After adding production code, the test will compile
• The test will now run, and fail because no logic is written yet
• Make the test pass by writing production code that meets the expectations of your
test
• Refactor your code
8. Benefits of TDD
• One of the biggest benefits of TDD nobody tells you about is that by seeing a test
fail, and then seeing it pass without changing the test, you’re basically testing
the test itself
10. NUnit attributes
[TestFixture]
public class LogAnalyzerTests
{
[Test]
public void
IsValidFileName_BadExtension_ReturnsFalse()
{
LogAnalyzer analyzer = new LogAnalyzer();
bool result =
analyzer.IsValidLogFileName("filewithbadextension
.foo");
Assert.False(result);
}
}
A unit test usually
comprises three main
actions
1. Arrange objects,
creating and setting
them up as necessary
2. Act on an object
3. Assert that something is
as expected
11. The Assert class
• Assert.True (some Boolean expression)
• Assert.False (some Boolean expression)
• Assert.AreEqual(2, 1+1, "Math is broken");
• Assert.AreSame(int.Parse("1"),int.Parse("1"),"this test should fail")
TDD - Red-Green-
Refactor
1. start with a failing test
2. pass it
3. make your code
readable and
more maintainable
15. Setup and teardown
[TestFixtureSetUp] and
[TestFixtureTearDown] allow setting up
state
once before all the tests in a specific class
run and once after all the tests have been
run (once per test fixture)
You almost never, ever use TearDown or
TestFixture methods in unit test projects
If you do, you’re very likely writing an
integration test, where you’re touching the
filesystem or a database, and you need to clean
up the disk or the DB after the tests.
Use it only to “reset” the state of a static variable
or singleton in memory
between tests
16. Checking for expected exceptions
public class LogAnalyzer
{
public bool IsValidLogFileName(string
fileName)
{
…
if (string.IsNullOrEmpty(fileName))
{
throw new ArgumentException(
"filename has to be provided");
}
…
}
}
[Test]
[ExpectedException(typeof(ArgumentException),
ExpectedMessage ="filename has to be
provided")]
public void
IsValidFileName_EmptyFileName_ThrowsException
()
{
m_analyzer.IsValidLogFileName(string.Empty);
}
private LogAnalyzer MakeAnalyzer()
{
return new LogAnalyzer();
}
Factory Method
19. State-based testing
State-based testing (also called state
verification) determines whether
the exercised method worked correctly
by examining the changed behavior
of the system under test and its
collaborators (dependencies) after the
method
is exercised.
20. Stubs
• External Dependency
• An external dependency is an object in your system that your code under test interacts
with and over which you have no control. (Common examples are filesystems, threads,
memory, time, and so on.)
• Stub
• A stub is a controllable replacement for an existing dependency (or collaborator) in the
system. By using a stub, you can test your code without dealing with the dependency
directly
21. Stub
• Your method has a direct
dependency on the filesystem. The
design of the object model under test
inhibits you from testing it as a unit
test; it promotes integration testing.
22. Stub
• Seams
Seams are places in your code where you
can plug in different functionality, such
as
stub classes,
adding a constructor parameter,
adding a public settable property,
making a method virtual so it can be
overridden,
Or externalizing a delegate as a
parameter or property so that it can be
set from outside a class.
Eg: IExtensionManager is a Seam
23. Fake objects
• Seams
Seams are places in your code where you
can plug in different functionality, such
as
stub classes,
adding a constructor parameter,
adding a public settable property,
making a method virtual so it can be
overridden,
Or externalizing a delegate as a
parameter or property so that it can be
set from outside a class.
Eg: IExtensionManager is a Seam