Unit tests give developers and testers a quick way to look for logic errors in the methods of classes in Visual C#, Visual Basic, and Visual C++ projects. A unit test can be created one time and run every time that source code is changed to make sure that no bugs are introduced.
2. Anatomy of a Unit Test
• Unit tests give developers and testers a quick way to look for logic
errors in the methods of classes in Visual C#, Visual Basic, and Visual
C++ projects. A unit test can be created one time and run every time
that source code is changed to make sure that no bugs are
introduced.
• An unit is the smallest testable part of an application. An unit could
be an entire module, but is more commonly an individual function or
procedure. In object-oriented programing a unit is often an entire
interface, such as a class, but it could be an individual method as
well.
• Unit tests are created by developers or occasionally by testers during
the development process.
3. One more time
• Unit testing is not about finding bugs
• Unit tests, by definition, examine each unit of your code separately
Goal Strongest technique
Finding bugs (things that don’t work as
you want them to)
Manual testing (sometimes also
automated integration tests)
Detecting regressions (things that used to
work but have unexpectedly stopped
working)
Automated integration tests (sometimes
also manual testing, though time-
consuming)
Designing software components robustly Unit testing (within the TDD process)
(Note: there’s one exception where unit tests do effectively detect bugs. It’s when you’re refactoring, i.e.,
restructuring a unit’s code but without meaning to change its behavior. In this case, unit tests can often tell you
if the unit’s behavior has changed.)
4. Visual Studio unit test tools includes
• Test Explorer. Test Explorer lets you run unit tests and view their
results. Test Explorer can use any unit test framework, including a
third-party framework, that has an adapter for the Explorer.
• Microsoft unit test framework for managed code. The Microsoft unit
test framework for managed code is installed with Visual Studio and
provides a framework for testing .NET code.
• Microsoft unit test framework for C++. The Microsoft unit test
framework for C++ is installed with Visual Studio and provides a
framework for testing native code.
6. Microsoft Unit Testing Framework for C++
#include "stdafx.h"
#include <CppUnitTest.h>
#include "..MyProjectUnderTestMyCodeUnderTest.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
TEST_CLASS(TestClassName)
{
public:
TEST_METHOD(TestMethodName)
{
// Run a function under test here.
Assert::AreEqual(expectedValue, actualValue, L"message", LINE_INFO());
}
}
• Writing Unit tests for C/C++ with the Microsoft Unit Testing
Framework for C++
7. Microsoft Unit Test Framework for Managed
Code
// unit test code
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace BankTests
{
[TestClass]
public class BankAccountTests
{
[TestMethod]
public void TestMethod1()
{
}
}
}
• Creating and Running Unit Tests for Managed Code
9. What to test
• Every public member of a class
• For each method you are testing you should include tests for the following:
• To confirm that the methods meet the requirements associated with them. Thus the test should verify that the
function does what it is supposed to do.
• To confirm the expected behavior for boundary and special values.
• To confirm that exceptions are thrown when expected.
• Unit tests should test one method only. This allows you to easily identify what failed if the test
fails.
• Unit tests should not be coupled together, therefore one unit test CANNOT rely on another unit
test having completed first.
• Units tests should use realistic data
• Unit tests should use small and simple data sets.
• How?
10. Isolating Code Under Test
• Isolate the code you are testing by replacing other parts of the
application with stubs or mocks.
• A stub replaces a class with a small substitute that implements the
same interface.
• To use stubs, you have to design your application so that each component
depends only on interfaces, and not on other components.
• Mocking is a very powerful tool that allows you to simulate
components in your unit environment and check how your code
operates within this environment.
• Mocking allows you to avoid creating Fake objects of any kind, and results in
fast executing code with a very high test coverage.
11. Dependency Injection (DI) approach
• Dependency injection (DI) is a technique for achieving
loose coupling between objects and their
collaborators, or dependencies.
• Rather than directly instantiating collaborators, or
using static references, the objects a class needs in
order to perform its actions are provided to the class
in some fashion.
• Most often, classes will declare their dependencies via
their constructor, allowing them to follow the Explicit
Dependencies Principle. This approach is known as
“constructor injection”.
• Methods and classes should explicitly require (typically
through method parameters or constructor parameters) any
collaborating objects they need in order to function correctly.
• Dependency injection is used a lot to make code more
testable.
class NeedsFoo
{
IFoo* foo;
public:
NeedsFoo(IFoo* foo) : foo(foo) { }
~NeedsFoo() { }
// Methods using the foo
};
[Export(typeof(INeedsFoo))]
[PartCreationPolicy(CreationPolicy.Shared)]
internal class NeedsFoo : INeedsFoo
{
[ImportingConstructor]
public NeedsFoo([Import]IFoo foo)
{
}
}
12. Good time to refactor code
public class DefaultAction : IActionResult
{
public DefaultAction()
{
_application = IoC.Get<IApplication>();
_inputService = IoC.Get<IInputService>();
}
}
13. One more
• Classes with implicit dependencies cost more to maintain than those
with explicit dependencies.
• They are more difficult to test because they are more tightly coupled
to their collaborators.
• They are more difficult to analyze for side effects, because the entire
class’s codebase must be searched for object instantiations or calls to
static methods.
• They are more brittle and more tightly coupled to their collaborators,
resulting in more rigid and brittle designs.
14. Unit test example (stub)
[TestMethod]
public void FillingFillsOrder()
{
var order = new Order(TALISKER, 50);
var mock = new MockWarehouse();
order.Fill(mock);
Assert.IsTrue(order.IsFilled);
Assert.AreEqual(TALISKER, mock.RemovedProductName);
Assert.AreEqual(50, mock.RemovedQuantity);
}
15. Unit test with Moq (.NET framework)
class ConsumerOfIUser
{
public int Consume(IUser user)
{
return user.CalculateAge() + 10;
}
}
[TestMethod]
public void TestConsume()
{
var userMock = new Mock<IUser>();
userMock.Setup(u => u.CalculateAge()).Returns(10);
var consumer = new ConsumerOfIUser();
var result = consumer.Consume(userMock);
Assert.AreEqual(result, 20); //should be true
}
16. Code Coverage
• To determine what proportion of
your project's code is actually being
tested by coded tests such as unit
tests, you can use the code coverage
feature of Visual Studio. To guard
effectively against bugs, your tests
should exercise or 'cover' a large
proportion of your code.
• Code coverage analysis can be
applied to both managed (CLI) and
unmanaged (native) code.
17. Test-Driven Development (TDD)
• Test-driven development (TDD) is a software development process
that relies on the repetition of a very short development cycle:
• requirements are turned into very specific test cases, then the software is
improved to pass the new tests, only.
• TDD is a software development process that relies on the repetition
of a very short development cycle:
• first the developer writes a failing test case that defines a desired
improvement or new function;
• then produces code to pass the test;
• and finally refactors the new code to acceptable standards.
19. Links
• Verifying Code by Using Unit Tests
• Writing Great Unit Tests: Best and Worst Practices
• Mocks, Stubs and Fakes: it’s a continuum
• Test-driven development and unit testing with examples in C++
• Explicit Dependencies Principle
• .NET Moq framework. Quickstart
• Using Code Coverage to Determine How Much Code is being Tested