Skip to main content

Bob the builder

I recently started a new project which is very focused on having good test coverage which is great goal to have.  However, looking through their tests I started to notice a lot of setup code which was very similar and looked a lot like the following:

   1: [TestMethod]
   2: public void WhenTheAddressRepositoryIsAskedToAPersistAddressesItShouldCorrectlyPersistThoseAddresses()
   3: {
   4:     // Arrange
   5:     var addressesToPersist = new List<Address>();
   6:  
   7:     var address = new Address
   8:                           {
   9:                               AddressLine1 = Guid.NewGuid().ToString(),
  10:                               AddressLine2 = Guid.NewGuid().ToString(),
  11:                               AddressLine3 = Guid.NewGuid().ToString(),
  12:                               AddressLine4 = Guid.NewGuid().ToString(),
  13:                               City = Guid.NewGuid().ToString(),
  14:                               County = Guid.NewGuid().ToString(),
  15:                               CountryCode = Guid.NewGuid().ToString(),
  16:                               Postcode = Guid.NewGuid().ToString()
  17:                           };
  18:     addressesToPersist.Add(address);
  19:  
  20:     var address1 = new Address
  21:                            {
  22:                                AddressLine1 = Guid.NewGuid().ToString(),
  23:                                AddressLine2 = Guid.NewGuid().ToString(),
  24:                                AddressLine3 = Guid.NewGuid().ToString(),
  25:                                AddressLine4 = Guid.NewGuid().ToString(),
  26:                                City = Guid.NewGuid().ToString(),
  27:                                County = Guid.NewGuid().ToString(),
  28:                                CountryCode = Guid.NewGuid().ToString(),
  29:                                Postcode = Guid.NewGuid().ToString()
  30:                            };
  31:     addressesToPersist.Add(address1);
  32:  
  33:     var addressRepository = new AddressRepository();
  34:     
  35:     // Act
  36:     addressRepository.Persist(addressesToPersist);
  37:     var actualPersistedAddresses = addressRepository.GetAll();
  38:     
  39:     // Assert
  40:     Assert.IsNotNull(actualPersistedAddresses);
  41:     Assert.AreEqual(2, actualPersistedAddresses.Count);
  42: }

Now the above code isn’t all that bad in a single test but what happens when you start to write more tests?  Well you could copy and paste the code for creating addresses from test to test which will certainly work but you end up with a lot of very similar code which you have to maintain going forward and update whenever a new address property is added or removed.  All this sounds like a lot of work plus it goes against the DRY principle.  DRY for those of you who don’t know means “Don’t Repeat Yourself”.  The principle encourages that duplication within an application is removed as every line of  code written has to be maintained and each line of code can cause bugs. More importantly the principle is about having a single source of knowledge within a system and then using that source to generate instances of that knowledge. In this case the instances of knowledge would be the address objects which are being created within each unit test.  The question then is how do we create something which we can use as the source of that knowledge?

Enter the builder

That single source of knowledge within the project I’m working on is provided by using the object builder pattern. Using this pattern we can have a single and consistent approach to creating the entities within tests and the ability to easily extend those entities within our domain and test data. We can also chain the builders together to create complex test data very quickly.

So how do you create a builder? Well below is my implementation of an address builder to get you going.

   1: public class AddressBuilder : BuilderBase<AddressBuilder, Address>
   2: {
   3:     private int id;
   4:     private string addressLine1 = GetUniqueValueFor();
   5:     private string addressLine2 = GetUniqueValueFor();
   6:     private string addressLine3 = GetUniqueValueFor();
   7:     private string addressLine4 = GetUniqueValueFor();
   8:     private string city = GetUniqueValueFor();
   9:     private string countryCode = "GB";
  10:     private string postCode = "SE1 9EU";
  11:     private string county = "London";
  12:  
  13:     public AddressBuilder WithId(int id)
  14:     {
  15:         this.id = id;
  16:         return this;
  17:     }
  18:    
  19:     public AddressBuilder WithAddressLine1(string addressLine1)
  20:     {
  21:         this.addressLine1 = addressLine1;
  22:         return this;
  23:     }
  24:  
  25:     public AddressBuilder WithAddressLine2(string addressLine2)
  26:     {
  27:         this.addressLine2 = addressLine2;
  28:         return this;
  29:     }
  30:  
  31:     public AddressBuilder WithAddressLine3(string addressLine3)
  32:     {
  33:         this.addressLine3 = addressLine3;
  34:         return this;
  35:     }
  36:  
  37:     public AddressBuilder WithAddressLine4(string addressLine4)
  38:     {
  39:         this.addressLine4 = addressLine4;
  40:         return this;
  41:     }
  42:  
  43:     public AddressBuilder WithCity(string city)
  44:     {
  45:         this.city = city;
  46:         return this;
  47:     }
  48:  
  49:     public AddressBuilder WithCountry(string countryCode)
  50:     {
  51:         this.countryCode = countryCode;
  52:         return this;
  53:     }
  54:  
  55:     public AddressBuilder WithPostCode(string postCode)
  56:     {
  57:         this.postCode = postCode;
  58:         return this;
  59:     }
  60:  
  61:     public AddressBuilder WithCounty(string county)
  62:     {
  63:         this.county = county;
  64:         return this;
  65:     }
  66:  
  67:     public override Address Build()
  68:     {
  69:         var address = new Address
  70:                           {
  71:                               Id = this.id,
  72:                               AddressLine1 = this.addressLine1,
  73:                               AddressLine2 = this.addressLine2,
  74:                               AddressLine3 = this.addressLine3,
  75:                               AddressLine4 = this.addressLine4,
  76:                               City = this.city,
  77:                               CountryCode = this.countryCode,
  78:                               County = this.county,
  79:                               Postcode = this.postCode
  80:                           };
  81:  
  82:         return address;
  83:     }
  84: }

As you can see the code behind the builder is really very simple with default values assigned to the properties which can then be explicitly set using the “With” methods on the builder. When I’m using builders I also like to add a base for them which provides default behaviour.

   1: public abstract class BuilderBase<TBuilder, TBuild> where TBuilder : BuilderBase<TBuilder, TBuild>
   2: {
   3:     /// <summary>
   4:     /// Builds this instance.
   5:     /// </summary>
   6:     /// <returns></returns>
   7:     public abstract TBuild Build();
   8:  
   9:     /// <summary>
  10:     /// Builds the many.
  11:     /// </summary>
  12:     /// <param name="number">The number.</param>
  13:     /// <returns></returns>
  14:     public List<TBuild> BuildMany(int number)
  15:     {
  16:         var result = new List<TBuild>();
  17:  
  18:         for (int i = 0; i < number; i++)
  19:         {
  20:             var builtItem = this.Build();
  21:             result.Add(builtItem);
  22:         }
  23:  
  24:         return result;
  25:     }
  26:  
  27:     /// <summary>
  28:     /// Gets the unique value for.
  29:     /// </summary>
  30:     /// <returns></returns>
  31:     protected static string GetUniqueValueFor()
  32:     {
  33:         return Guid.NewGuid().ToString();
  34:     }
  35: }

So now we have the address builder this put it all together to create our new and improved unit test.

   1: [TestMethod]
   2: public void WhenTheAddressRepositoryIsAskedToAPersistAddressesItShouldCorrectlyPersistThoseAddresses()
   3: {
   4:     // Arrange
   5:     var addressesToPersist = new AddressBuilder().BuildMany(2);
   6:     var addressRepository = new AddressRepository();
   7:     
   8:     // Act
   9:     addressRepository.Persist(addressesToPersist);
  10:     var actualPersistedAddresses = addressRepository.GetAll();
  11:     
  12:     // Assert
  13:     Assert.IsNotNull(actualPersistedAddresses);
  14:     Assert.AreEqual(2, actualPersistedAddresses.Count);
  15: }

As you can see the duplicate code for creating each address is now gone and we have a nice simple method for creating as many address as we want using the “BuildMany” method provided by the base builder. Well that’s it for now. The complete source code for this example can be found at http://cid-468e9f9e14e99f80.office.live.com/self.aspx/.Public/Blog.Builders.zip

Comments

Popular posts from this blog

X509 certificate encryption fun :-)

Recently I needed to encrypt data on a server and allow a limited number of service accounts the ability to decrypt that data so it was as safe as possible. The approach I took to achieve this was by using a X509 certificate and it's ability to allow you to encrypt information via it's public key and decrypt that information through the private key. The key parts of this approach are: - Create a certificate - Ensure the KeySpec of the certificate is set up correctly to allow for encryption e.g. "KeyExchange" or "None" if you are doing this via PowerShell - Set the security on the private keys so only specific user accounts can access it and decrypt information encrypted via the public key. Step 1 - Create a certificate to use The easiest way to get a quick example going is via PowerShell to create a dummy root certificate and the one we will use for encrypting and decrypting. $rootCert = New-SelfSignedCertificate -CertStoreLocation Cert:\LocalMachine\My -Dns

Why poor tests are worse than no tests

It's been awhile since I wrote my last blog post so I thought I would resume with a subject close to my heart...unit testing. Unit testing is tricky and lots of people don't focus enough on the key pillars that make up a good test: Trustworthy - Can the test be run multiple times and work in the same way each time? A test which works sometimes and fails randomly when a build happens during continuous integration(CI) is just going to be ignored and has no benefit to the team. Worse still, a bad test can give you a false impression that everything is fine when really it's not.   Readable - Can you look at the name of the test and work out what it's meant to do? For example, a test named "It_works_and_doesnt_fail" isn't as good as "It_will_add_a_valid_order_without_errors". Maintainable - Is your test simple to setup and refactor when code changes are made in the rest of the system? The

SharePoint - Search Service Application (SSA) - Attempted to perform an unauthorized operation

On my current project I needed to adjust and add some search mapping via SharePoint's Central Administration web site. This should have been very straight forward as you have the ability to add managed properties and mappings easily via the UI. However, when I went to save my changes I got the error "The settings could not be saved because of an internal error: Attempted to perform an unauthorized operation". Now this was very confusing as I am administrator on the server and added into all of the correct SharePoint groups. I also tried the same action via PowerShell and got the same error.   After a few hours of research and head scratching I managed to get to the bottom of the problem which is the way my user account had been added as an administrator to the server. In the company I work for to make it easier to manage the administrators on a server a group is created in active directory called " servername_admins ". This group is added to the local administra