Remove data structures noise from your tests with builders

Among other qualities good tests should be easy to read, quick to understand. When the test requires complex data structures to be sent to the SUT or to be part of a stubbed answer, it takes longer to read. Moreover those structures use to evolve as the production code does causing too many changes in the tests in order to adapt them. An indirection level in between the test and the production code helps improve readability and ease of maintenance. Builders come to the rescue. I often overload builder methods to support several data structures and then apply the conversions internally.

As an example, this is the setup of one of our tests before the final refactor:

  1. [Test] public async void
  2. raise_multiple_choices_event_on_equipment_selection () {
  3. SetupViewModelWithMockService();
  4. var selectedEquipment = new Equipment { Code = "PR" };
  5. var oneEquipment = new Equipment { Code = "PR1"};
  6. var otherEquipment = new Equipment { Code = "PR2"};
  7. var equipments = new List<Equipment>{ selectedEquipment, oneEquipment, otherEquipment };
  8. var multipleChoices = new List<CompulsoryCombinationChoice> {
  9. new CompulsoryCombinationChoice(new List<CompulsoryCombinationItem> {
  10. new CompulsoryCombinationItem(oneEquipment.Code, CatalogItemTypes.Equipment)
  11. }),
  12. new CompulsoryCombinationChoice(new List<CompulsoryCombinationItem> {
  13. new CompulsoryCombinationItem(otherEquipment.Code, CatalogItemTypes.Equipment)
  14. })
  15. };
  16. ACatalog.MockingDependenciesOf(vm)
  17. .WithEquipments(equipments)
  18. .ResolvingCompulsoryCombinationsAs(multipleChoices)
  19. .Configure();
  20. /* act ... */
  21. /* assert ... */
  22.  

Imagine how ugly it was before the "ACatalog" builder. And this is the test after the builder was overloaded to supply a more comfortable API:

  1. [Test] public async void
  2. raise_multiple_choices_event_on_equipment_selection() {
  3. SetupViewModelWithMockService();
  4. var theEquipment = "PR";
  5. var equipment1 = "PR1";
  6. var equipment2 = "PR2";
  7. ACatalog.MockingDependenciesOf(vm)
  8. .WithEquipments(theEquipment, equipment1, equipment2)
  9. .ResolvingCompulsoryCombinationsAs(
  10. MultipleCompulsoryCombinationChoices(
  11. equipment1, equipment2))
  12. .Configure();
  13. /* act ... */
  14. /* assert ... */
  15.  
Enjoyed reading this post?
Subscribe to the RSS feed and have all new posts delivered straight to you.
  • Johan S. Cortes

    Is ACatalog builder used in production also?

    if not, do you consider a good option to create the builder only for test purposes?

    Thanks for sharing 😀

  • http://www.carlosble.com/ Carlos Ble

    Hi Johan,
    Most of our builders are only used in the tests, never in the production code. Test could should be clean, we care about it as much as we care about production code 😉