Unit Testing / Mocking Techniques

Introduction to Unit Testing

  • Unit Testing
    • The primary goal of unit testing is to take the smallest piece of testable software in the application, isolate it from the remainder of the code, and determine whether it behaves exactly as you expect under various conditions.
  • Benefits
    • Unit testing has proven its value in that a large percentage of defects are identified during its use. If you detect and solve bugs closer to the time they are introduced, it’s a lot faster than having to locate, debug, and resolve a bug in the future.
    • You know that your code works as you expect it to work. With unit tests in place, you know that your foundation code is dependable.
    • It’s a good way to test first hand how your API is going to be used.

Unit Testing verses Integration Testing

The difference between unit testing and integration testing is important to recognize.

  • What is a unit test?
    • A unit test is code that tests one single method or function and checks the correctness of some assumptions afterwards. If the assumptions turn out to be wrong, the unit test has failed. A unit test should have a very narrow and well defined scope. Complex dependencies and interactions to the outside world are stubbed or mocked.
  • What is an integration test?
    • An Integration test means testing two or more dependent software modules as a group. This can be anything from testing the integration between two classes, to testing the integration of multiple components in the production environment. Integration testing includes performance tests, functional tests, system tests, acceptance tests, smoke tests, etc.

Properties of a good unit test

  • Automated: It can be executed as part of an automated build process.
  • Repeatable: It can be executed repeatedly by anyone on the development team.
  • Consistent: Every time you run it, you get the same result.
  • In Memory: It has no “hard” dependencies on anything not in memory (such as file system, databases, network, web services). Use mocking for all external services or state.
  • Single concern: Tests one single feature or behavior.
  • Independent: No test should depend on any other test or on the order of execution.
  • Fast: It should run quickly.

Unit Testing Frameworks

Since unit tests concern themselves with individual methods, you need something to create an instance of the class and invoke methods to test.

  • What is a unit testing framework?
    • A unit testing framework supports the writing of a suite of tests.
    • A framework provides a test runner that runs the test, indicates the status while running and provides the results of your test run. This process can be automated by command line.
    • Microsoft supplies MSTest which is built into Visual Studio. JUnit is another testing framework for java development.
  • Why not use console applications to test our classes?
    • Looking at the output to determine whether it worked or didn’t work can be very cumbersome.
    • It doesn’t really provide a way to report on what worked and didn’t work.
    • Cannot be automated.

Unit Test Structure

  • Three Main Actions
    • Arrange: Arrange objects, creating and setting them up as necessary.
    • Act: Act on an object. Call the method being tested.
    • Assert: Assert that something is as expected. Verifying that your code works as you expect it to work is the most important part of unit testing.
  • Test Attributes
    • MSTest, as well as other testing frameworks, use an attribute scheme to recognize and load tests.
    • Attributes needed
      • [TestClass] – denotes a class that holds automated tests.
      • [TestMethod] – can be put on a method to denote it as an automated test to be invoked.
    • Optional Attributes
      • [ClassInitialize] and [ClassCleanup]
      • [TestInitialize] and [TestCleanup]

Asserting for Expected Results

  • Use Assert to verify specific functionality
    • Assert classes have static methods that check the passed in arguments.
    • Its purpose is to declare that a specific assumption is supposed to exist and alert us if these assumptions have failed.
  • Examples
    • Assert.AreEqual(2, 1+1);
    • Assert.IsTrue(IsValidFileName);
  • Kinds of Asserts (MSTest)
    • Assert – In your test method, you can call any number of methods of the Assert class, such as Assert.AreEqual().
    • StringAssert – Use the StringAssert class to compare strings. This class contains a variety of useful methods such as StringAssert.Contains, StringAssert.Matches, and StringAssert.StartsWith.
    • CollectionAssert – Use the CollectionAssert class to compare collections of objects, and to verify the state of one or more collections.

Introduction to Mocking Dependencies

  • When do we need mocks?
    • When your method relies on another object over which you have no control (for example, when you can’t control what that dependency returns or how it behaves)
    • When your method relies on another object which doesn’t work yet.
  • What can you do then?
    • Find the interface or API for that method
    • Replace the underlying implementation of that interface with something you have control over.

Manually Written Mocks (fakes)

  • Purpose
    • Manually written mocks can be used for unit testing, integration testing as well as manual testing in an application.
    • Using StructureMap profiles, you can swap between using the test mock and the real implementation
  • Issues when using manually written mocks
    • It takes time to write the mocks
    • It’s difficult to write for classes and interfaces that have many methods, properties and events
    • It’s hard to reuse mocks for other tests.

StuctureMap Profiles for use with Mock Objects

  • Using StructureMap profiles, you can setup fake implementations for your application using your mock objects

Mock Object Frameworks (isolation frameworks)

  • What is a mock object framework?
    • A reusable library that can create and configure mock objects at runtime.
  • Why use isolation frameworks?
    • Save the developer from writing repetitive code to test or simulate object interactions
    • Isolate methods (units) to be tested from it’s dependencies
  • Mocking Frameworks
    • Moq
    • RhinoMocks
    • FakeItEasy
    • NMock
    • JMockit

Introduction to Moq

  • Moq
    • Moq (pronounced “Mock”) is a mocking library for .NET developed from scratch to take full advantage of .NET 3.5 (i.e. Linq expression trees) and C# 3.0 features (i.e. lambda expressions).
  • Features
    • Strong-typed
    • Granular control over mock behavior with a simple MockBehavior enumeration (no need to learn what’s the theoretical difference between a mock, a stub, a fake, a dynamic mock, etc.)
    • Override expectations: can set default expectations in a test setup, and override as needed on tests
    • Pass constructor arguments
    • Intercept and raise events
    • Support for out/ref arguments
    • Easy to use
  • Basic Process to using Moq
    • Create an instance of Moq’s “Mock” class that takes an interface or class with virtual methods as a generic parameter.
    • Tell the Mock what you want to happen, specifying parameters, and even return values.
    • Get back the mocked interface which will behave in the way in which you told it to. Use this mocked interface in your code.
    • Call “Verify” or “VerifyAll” on the mock to ensure that what you said would happen actually happened. This step is not always required.

Moq examples

 

 

 

 

 

GitHub project: https://github.com/lorifpeterson/UnitTestDemo

References:

Speak Your Mind

*