Tag Archives: TDD
Building Testing into your SDLC

Testing software is critically important to ensuring quality. Automated tests provide a lower Mean Time to Feedback (MTTF) for errors as well as enable developer’s to make changes without fear of breaking things. The earlier in the SDLC that errors can be detected and corrected, the better. (See the Test Pyramid). As engineers on the platform we should practice TDD in order to generate a thorough bed of unit tests. Unit tests alone do not ensure that everything works as expected so we will need gradually more sophisticated forms of testing.

There are different approaches to testing software. This document chooses to articulate types of automated testing by the point in the SDLC at which it is executed and by what it covers. There may be different strategies for testing at each of these lifecycle points (e.g., deterministic, fuzz, property-based, load, perf, etc..)

SDLC StageTypeTargetWho Runs Them?Description
Design / Build TimeUnitSingle ApplicationEngineer, CIIn process, no external resources. Mock at the Architectural boundaries but otherwise avoid mocks where possible.
IntegrationSingle ApplicationEngineer, CIThese tests will mostly target the adapters for external systems (e.g., file io, databases, 3rd party API’s, 1st party API’s that are not the component under test.)

Integration tests differ from acceptance tests in that they should never fail to an issue with an external service.
Post Deployment to Test EnvironmentAcceptanceEntire System or PlatformCI, CDLargely black box, end-to-end testing.

For bonus points, tie failures into telemetry to see if your monitors are alerting you.
Manual UX TestingEntire System or PlatformEngineer, QA, UsersThis testing is qualitative and pertains to the “feel” of the platform with respect to the user experience.
Post Production ReleaseSmokeEntire System or PlatformEngineer, CDA small suite of manual tests to validate production configuration.
Synthetic TransactionsEntire System or PlatformSystemBlack box, end-to-end use-case testing, automated, safe for production. These tests are less about correctness and more about proving the service is running.
Other?This is not an exhaustive list.

Emphasize Unit Tests

In general, our heaviest investment in testing should be done at the time the code is written. This means that unit tests should far outweigh other testing efforts. Why?

Unit tests are very low-cost to write and have very low Mean Time to Feedback (MTTF). This means they have the greatest ROI of any other kind of test.

The other kinds of testing are important but they get more complex as you move through the SDLC. This makes covering finicky edge-cases challenging from both an implementation and maintenance perspective. Unit Tests don’t have these drawbacks provided you follow good TDD guidance.

TDD

TDD is the strongly preferred manner of writing unit tests as it ensures that all code written is necessary (required by a test) and correct. Engineers who are not used to writing code in a TDD style often struggle with the practice in the early stages. If this describes your experience, be satisfied with writing tests for the code you’ve written in the same commit until it starts to feel natural.

The activity of TDD consists of three steps:

  1. (RED) Write a failng unit test.
  2. (GREEN) Write enough productino code to make it pass.
  3. (REFACTOR) Now make the code pretty.

The unit tests you write should strive to obey the three laws of TDD:

  1. Don’t write any production code unless it is to make a failing unit test pass.
  2. Don’t write any more of a unit test than is sufficient to fail; and compilation failures are failures.
  3. Don’t write any more production code than is sufficient to pass the one failing unit test.

Good unit tests have the following attributes:

  1. The test must fail reliably for the reason intended.
  2. The test must never fail for any other reason.
  3. There must be no other test that fails for this reason.

Further Reading

It’s impossible to fully convey the scope of what you should know about test automation in this document. Below are some resources you may be interested in as you move through your career.

  1. Test Driven Development: By Example by Kent Beck
  2. The Art of Unit Testing: 2nd Edition by Roy Osherove
  3. Working Effectively With Legacy Code by Michael Feathers
  4. Refactoring: Improving the Design of Existing Code (2nd Edition) by Martin Fowler
Don’t Unit Test NHibernate: Use Generic Repository

I was reading this stack overflow question: How can I solve this: Nhibernate Querying in an n-tier architecture?

The author is trying to abstract away NHibernate and is being counseled rather heavily not to do so. In the comments there are a couple of blog entries by Ayende on this topic:

The false myth of encapsulating data access in the DAL

Architecting in the pit of doom the evils of the repository abstraction layer

Ayende is pretty down on abstracting away NHIbernate. The answers on StackOverflow push the questioner toward just standing up an in-memory Sqlite instance and executing the tests against that.

The Sqlite solution is pretty painful with complex databases. It requires that you set up an enormous amount of data that isn’t really germane to your test in order to satisfy FK and other constraints. The ceremony of creating this extra data clutters the test and obscures the intent. To test a query for employees who are managers, I’d have to create Departments and Job Titles and Salary Types etc., etc., etc.. Dis-like.

What problem am I trying to solve?

In the .NET space developers tend to want to use LINQ to access, filter, and project data. NHibernate (partially) supports LINQ via an extension method off of ISession. Because ISession.Query<T> is an extension method, it is not stubbable with free mocking tools such as RhinoMocks, Moq, or my favorite: NSubstitute. This is why people push you to use the Sqlite solution—because the piece of the underlying interface that you want to use most of the time is not built for stubbing.

I think that a fundamental problem with NHibernate is that it is trying to serve 2 masters. On the one hand it wants to be a faithful port of Hibernate. On the other, it wants to be a good citizen for .NET. Since .NET has LINQ and Java doesn’t, the support for LINQ is shoddy and doesn’t really fit in well the rest of the API design. LINQ support is an “add-on” to the Java api, and not a first-class citizen. I think this is why it was implemented as an extension method instead of as part of the ISession interface.

I firmly disagree with Ayende on Generic Repository. However, I do agree with some of the criticisms he offers against specific implementations. I think his arguments are a little bit of straw man, however. It is possible to do Generic Repository well.

I prefer to keep my IRepository interface simple:

    public interface IRepository : IDisposable
    {
        IQueryable<T> Find<T>() where T: class;

        T Get<T>(object key) where T : class;

        void Save<T>(T value) where T: class;

        void Delete<T>(T value) where T: class;

        ITransaction BeginTransaction();

        IDbConnection GetUnderlyingConnection();
    }

 

Here are some of my guidelines when using a Generic Repository abstraction:

  • My purpose in using Generic Repository is not to “hide” the ORM, but
    • to ease testability.
    • to provide a common interface for accessing multiple types of databases (e.g., I have implemented IRepository against relational and non-relational databases) Most of my storage operations follow the Retrieve-Modify-Persist pattern, so Find<T>, Get<T>, and Save<T> support almost everything I need.
  • I don’t expose my data models outside of self-contained operations, so Attach/Detach are not useful to me.
  • If I need any of the other advanced ORM features, I’ll use the ORM directly and write an appropriate integration test for that functionality.
    • I don’t use Attach/Detach, bulk operations, Flush, Futures, or any other advanced features of the ORM in my IRepository interface. I prefer an interface that is clean, simple, and useful in 95% of my scenarios.
  • I implemented Find<T> as an IQueryable<T>. This makes it easy to use the Specification pattern to perform arbitrary queries. I wrote a specification package that targets LINQ for this purpose.
    • In production code it is usually easy enough to append where-clauses to the exposed IQueryable<T>
    • For dynamic user-driven queries I will write a class that will convert a flat request contract into the where-clause needed by the operation.
  • I expose the underlying connection so that if someone needs to execute a sproc or raw sql there is a convenient way of doing that.
Testing Ninject Bindings

I recently had a subtle production bug introduced by creating more than one Ninject binding for a given interface to the same instance.

I wanted to be able to see what bindings existed for a given interface, but Ninject does not provide an easy way to do that.

This gist contains an extension method I wrote (with the help of a StackOverflow article) to acquire this information.

As this code relies on using reflection to get a private member variable, this code is brittle in the face of a change in the implementation of KernelBase. In the meantime, it works on my machine.

    public class InjectionBinding
    {
        public Type RegistrationKey { get; set; }
        public IList<object> Implementations { get; set; }
        public Type[] GetImplementationTypes()
        {
            return Implementations.Select(row => row.GetType()).ToArray();
        }
    }
    
    // relies on the implementation of KernelBase since
    // Ninject does not allow you to query bindings via
    // its api.
    public static class NinjectExtensions
    {
        public static IEnumerable<InjectionBinding> GetImplementations(this KernelBase self, Func<Type, bool> criteria = null )
        {
            if (criteria == null)
                criteria = type => true;
            const BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;

            // Retrieve a FieldInfo instance corresponding to the field
            var field = typeof(KernelBase).GetField("bindings", flags);

            var bindingsMap = (Multimap<Type, IBinding>)field.GetValue(self);

            var allBindings = bindingsMap.Keys.SelectMany(key => bindingsMap[key]).ToList();
            var allBindingsMatchingCriteria = allBindings
                .Select(row => row.Service)
                .Where(row => criteria.Invoke(row))
                .ToList()
                ;

            var keyValues = from instance in allBindingsMatchingCriteria
                            select new InjectionBinding
                            {
                                RegistrationKey = instance,
                                Implementations = self.GetAll(instance).ToList(), // instance.Implementations.ToList(),
                            };


            return keyValues;

        } 
    }

Recursive Mocks with Rhino Mocks and NSubstitute

I just learned that you could do this:

    public interface IMapper
    {
        IMapperLink From<TInput>(TInput input);
    }
    
    public interface IMapperLink
    {
        TOutput To<TOutput>();
    }

    [Test]
    public void BeforeRhinoMocksRecursiveMocks()
    {
        var mapper = MockRepository.GenerateMock<IMapper>();
        var mapperLink = MockRepository.GenerateMock<IMapperLink>();
        
        mapper.Expect(mock => mock.From(5)).Return(mapperLink);
        mapperLink.Expect(mock => mock.To<string>()).Return("Test");

        var result = mapper.From(5).To<string>();
        Assert.That(result, Is.EqualTo("Test"));
    }

    [Test]
    public void UsingRhinoMocksRecursiveMocks()
    {
        var mapper = MockRepository.GenerateMock<IMapper>();
        mapper.Expect(mock => mock.From(5).To<string>()).Return("Test");

        var result = mapper.From(5).To<string>();
        Assert.That(result, Is.EqualTo("Test"));
    }

    [Test]
    public void UsingNSubstituteRecursiveMocks()
    {
        var mapper = Substitute.For<IMapper>();
        mapper.From(5).To<string>().Returns("Test");

        var result = mapper.From(5).To<string>();
        Assert.That(result, Is.EqualTo("Test"));
    }
    
    [Test]
    public void UsingNSubstituteWithMultipleRecursiveMocks()
    {
        var mapper = Substitute.For<IConverterApi>();
        mapper.From(5).To<string>().Returns("Test");
        mapper.From("Seven").To<double>().Returns(7.0);

        var firstResult = mapper.From(5).To<string>();
        Assert.That(firstResult, Is.EqualTo("Test"));

        var secondResult = mapper.From("Seven").To<double>();
        Assert.That(secondResult, Is.EqualTo(7.0));
    }
        
    [Test]
    public void UsingRhinoMocksWithMultipleRecursiveMocks()
    {
        var mapper = MockRepository.GenerateMock<IConverterApi>();
        mapper.Expect(mock => mock.From(5).To<string>()).Return("Test");

        // This test fails here.
        mapper.Expect(mock => mock.From("Seven").To<double>()).Return(7.0);

        var firstResult = mapper.From(5).To<string>();
        Assert.That(firstResult, Is.EqualTo("Test"));

        var secondResult = mapper.From("Seven").To<double>();
        Assert.That(secondResult, Is.EqualTo(7.0));
    }    

Update: 2013-01-25
Note that successive chained mocking calls to RhinoMocks fail. I now have a reason to prefer NSubstitute other than it’s beautifully simple API.

TDD Talking Point: TDD is more about API than Implementation

One of the points I tried to make in my talk about TDD yesterday is that TDD is more focused on the clarity and expressiveness of your code than on its actual implementation. I wanted to take a little time and expand on what I meant.

I used a Shopping Cart as an TDD sample. In the sample, the requirement is that as products are added to the shopping cart, the cart should contain a list or OrderDetails that are distinct by product sku. Here is the test I wrote for this case (this is commit #8 if you want to follow along):

[Test]
public void Details_AfterAddingSameProductTwice_ShouldDefragDetails()
{
    // Arrange: Declare any variables or set up any conditions
    //          required by your test.
    var cart = new Lib.ShoppingCart();
    var product = new Product() { Sku = "ABC", Description = "Test", Price = 1.99 };
    const int firstQuantity = 5;
    const int secondQuantity = 3;

    // Act:     Perform the activity under test.
    cart.AddToCart(product, firstQuantity);
    cart.AddToCart(product, secondQuantity);

    // Assert:  Verify that the activity under test had the
    //          expected results
    Assert.That(cart.Details.Count, Is.EqualTo(1));
    var detail = cart.Details.Single();
    var expectedQuantity = firstQuantity + secondQuantity;
    Assert.That(detail.Quantity, Is.EqualTo(expectedQuantity));
    Assert.That(detail.Product, Is.SameAs(product));
}

The naive implementation of AddToCart is currently as follows:

public void AddToCart(Product product, int quantity)
{
    this._details.Add(new OrderDetail()
                          {
                              Product = product, 
                              Quantity = quantity
                          });
}

 

This implementation of AddToCart fails the test case since it does not account for adding the same product sku twice. In order to get to the “Green” step, I made these changes:

public void AddToCart(Product product, int quantity)
{
    if (this.Details.Any(detail => detail.Product.Sku == product.Sku))
    {
        this.Details.First(detail => detail.Product.Sku == product.Sku).Quantity += quantity;           
    }
    else
    {
        this._details.Add(new OrderDetail()
        {
            Product = product,
            Quantity = quantity
        });                
    }

}

At this point, the test passes, but I think the above implementation is kind of ugly. Having the code in this kind of ugly state is still a value though because now I know I have solved the problem correctly. Let’s start by using Extract Condition on the conditional expression.

public void AddToCart(Product product, int quantity)
{
    var detail = this.Details.SingleOrDefault(d => d.Product.Sku == product.Sku);
    if (detail != null)
    {
        detail.Quantity += quantity;           
    }
    else
    {
        this._details.Add(new OrderDetail()
        {
            Product = product,
            Quantity = quantity
        });                
    }
}

The algorithm being used is becoming clearer.

  1. Determine if I have an OrderDetail matching the Product Sku.
  2. If I do, increment the quantity.
  3. If I do not, create a new OrderDetail matching the product sku and set it’s quantity.

It’s a pretty simple algorithm. Let’s do a little more refactoring. Let’s apply Extract Method to the lambda expression.

public void AddToCart(Product product, int quantity)
{
    var detail = GetProductDetail(product);
    if (detail != null)
    {
        detail.Quantity += quantity;           
    }
    else
    {
        this._details.Add(new OrderDetail()
        {
            Product = product,
            Quantity = quantity
        });                
    }
}

private OrderDetail GetProductDetail(Product product)
{
    return this.Details.SingleOrDefault(d => d.Product.Sku == product.Sku);
}

 

This reads still more clearly. This is also where I stopped in my talk. Note that it has not been necessary to make changes to the my test case because the changes I have made go to the private implementation of the class. I’d like to go a little further now and say that if I change the algorithm I can actually make this code even clearer. What if the algorithm was changed to:

  1. Find or Create an OrderDetail matching the product sku.
  2. Update the quantity.

In the first algorithm, I am taking different action with the quantity depending on whether or not the detail exists. In the new algorithm, I’m demoting the importance of whether the order detail already exists so that I can always take the same action with respect to the quantity. Here’s the naive implementation:

public void AddToCart(Product product, int quantity)
{
    OrderDetail detail;
    
    if (this.Details.Any(d => d.Product.Sku == product.Sku))
    {
        detail = this.Details.Single(d => d.Product.Sku == product.Sku); 
    }
    else
    {
        detail = new OrderDetail() { Product = product };
        this._details.Add(detail);
    }
    
    detail.Quantity += quantity;           
}

The naive implementation is a little clearer. Let’s apply some refactoring effort and see what happens.. Let’s apply Extract Method to the entire process of getting the order detail.

public void AddToCart(Product product, int quantity)
{
    var detail = GetDetail(product);

    detail.Quantity += quantity;
}

private OrderDetail GetDetail(Product product)
{
    OrderDetail detail;
    
    if (this.Details.Any(d => d.Product.Sku == product.Sku))
    {
        detail = this.Details.Single(d => d.Product.Sku == product.Sku); 
    }
    else
    {
        detail = new OrderDetail() { Product = product };
        this._details.Add(detail);
    }
    return detail;
}

This is starting to take shape. However, “GetDetail” does not really communicate that we may be creating a new detail instead of just returning an existing one. If we rename it to FindOrCreateOrderDetailForProduct, we may get that clarity.

public void AddToCart(Product product, int quantity)
{
    var detail = FindOrCreateDetailForProduct(product);

    detail.Quantity += quantity;
}

private OrderDetail FindOrCreateDetailForProduct(Product product)
{
    OrderDetail detail;
    
    if (this.Details.Any(d => d.Product.Sku == product.Sku))
    {
        detail = this.Details.Single(d => d.Product.Sku == product.Sku); 
    }
    else
    {
        detail = new OrderDetail() { Product = product };
        this._details.Add(detail);
    }
    return detail;
}

AddToCart() looks pretty good now. It’s easy to read, and each line communicates the intent of our code clearly. FindOrCreateDetailForProduct() on the other hand is less easy to read. I’m going to apply Extract Conditional to the if statement, and Extract Method to each side of the expression. Here is the result:

private OrderDetail FindOrCreateDetailForProduct(Product product)
{
    var detail = HasProductDetail(product) ? 
        FindDetailForProduct(product) : 
        CreateDetailForProduct(product);
    return detail;
}

private OrderDetail CreateDetailForProduct(Product product)
{
    var detail = new OrderDetail() { Product = product };
    this._details.Add(detail);
    return detail;
}

private OrderDetail FindDetailForProduct(Product product)
{
    var detail = this.Details.Single(d => d.Product.Sku == product.Sku);
    return detail;
}

private bool HasProductDetail(Product product)
{
    return this.Details.Any(d => d.Product.Sku == product.Sku);
}

Now I’ve noticed that HasProductDetail and FindDetailForProduct are only using the product sku. I’m going to change the signature of these methods to accept only the sku, and I’ll change the method names accordingly.

public void AddToCart(Product product, int quantity)
{
    var detail = FindOrCreateDetailForProduct(product);
    detail.Quantity += quantity;
}

private OrderDetail FindOrCreateDetailForProduct(Product product)
{
    var detail = HasDetailForProductSku(product.Sku) ? 
        FindDetailByProductSku(product.Sku) : 
        CreateDetailForProduct(product);
    return detail;
}

private OrderDetail CreateDetailForProduct(Product product)
{
    var detail = new OrderDetail() { Product = product };
    this._details.Add(detail);
    return detail;
}

private OrderDetail FindDetailByProductSku(string productSku)
{
    var detail = this.Details.Single(d => d.Product.Sku == productSku);
    return detail;
}

private bool HasDetailForProductSku(string productSku)
{
    return this.Details.Any(d => d.Product.Sku == productSku);
}

At this point, the AddToCart() method has gone through some pretty extensive refactoring. The basic algorithm has been changed, and the implementation of the new algorithm has been changed a lot. Now let me point something out: At no time during any of these changes did our test fail, and at no time during these changes did our test fail to express the intended behavior of the class. We made changes to every aspect of the implementation: We changed the order of the steps in the algorithm. We constantly added and renamed methods until we had very discrete well-named functions that stated explicitly what the code is doing. The unit test remained a valid expression of intended behavior despite all of these changes. This is what it means to say that a test is more about API than implementation. The unit-test should not depend on the implementation, nor does it necessarily imply a particular implementation.

Happy Coding!

TDD Presentation Resources

Tomorrow I will be giving a talk on TDD at CMAP. The demo code and outline I will be using can be found on bitbucket here.

Here is the outline for the talk:

  • I. Tools
    • A. Framework
    • B. Test Runner
    • C. Brains
  • II. Test Architecture
    • A. Test Fixture
    • B. Setup
    • C. Test Method
    • D. TearDown
  • III. Process
    • A. Red
    • B. Green.
    • C. Refactor.
    • D. Rinse and Repeat.
  • IV. Conventions
    • A. At least one testfixture per class.
    • B. At least one test method per public method.
    • C. Test Method naming conventions
      • i. MethodUnderTest_ConditionUnderTest_ExpectedResult
    • D. Test Method section conventions
      • i. Arrange
      • ii. Act
      • iii. Assert
  • V. Other Issues
    • A. Productivity Study
    • B. Testing the UI
      • i. Not technically possible without more tooling/infrastructure
      • ii. MVC patterns increate unit-test coverage.
      • iii. Legacy code.
        • a. Presents special problems.
        • b. Touching untested legacy code is dangerous.
        • c. Boy-Scout rule.
        • d. Use your own judgment
    • C. Pros and Cons
      • i. Pros
        • a. Quality.
        • b. Encourage a more loosely-coupled design.
        • c. Document the work that is done.
        • d. Regression testing.
        • e. Increased confidence in working code means changes are easier to make.
        • f. Encourages devs to think about code in terms of API instead of implementation.
          • 1. Makes code more readable.
          • 2. Readable code communicates intent more clearly.
          • 3. Readable code reduces the need for additional non-code documentation.
      • ii. Cons
        • a. Takes longer to develop.
        • b. Test code must be maintained as well.
        • c. Requires that devs adapt to new ways of thinking about code.
    • D. Notes