CHAPTER 9
For most of this book, we’ve been exploring FakeItEasy’s API from the perspective of creating fakes for dependencies that are injected into the SUT. We’ve learned a good amount on how to create, configure, and then assert calls to faked dependences so we can test our SUT.
But what happens when we fake the SUT?
Many times, we need to fake the SUT because the SUT is using inheritance in some fashion, and there is no other way for FakeItEasy to get involved (another great reason to use inheritance as your last resort, not your first). If we’re trying to get a hold of the behavior and expectations of members that are declared as protected virtual, protected abstract void, protected overrides, and virtual readonly, we need to fake the SUT in order to write the unit test.
I need to add this disclaimer here: I do not recommend faking the SUT unless you have to.
If this code is “overriding” code in the SUT via FakeItEasy configuration, then there is a chance the real code that you’re faking would never be tested. In other words, if you don’t watch yourself, you could end up releasing untested code to production.
Some readers may not think this is a big deal, but at my current job, we have almost 90 percent unit test coverage (the missing 10 percent are covered by integration tests), and our programming department takes great care to keep all code written covered 100 percent (or as close as possible) by unit tests.
That being said, let’s take a look at how to fake the SUT in this chapter, where the SUT is inheriting from an abstract class.
This is how we create a fake of our SUT:
var sut = A.Fake<ClassThatIsMySut>(); |
Code Listing 108: Creating a fake of the SUT
This syntax should look familiar to you by now. But this time, we’re not creating a fake of an interface that the SUT uses and injecting it in via the SUT’s constructor, but rather, creating a fake of the SUT itself.
Here is the overload of A.CallTo we’ll be using to fake the SUT:
// Summary: // Gets a configuration object allowing for further configuration of any call // to the specified faked object. // // Parameters: // fake: // The fake to configure. // // Returns: // A configuration object. public static IAnyCallConfigurationWithNoReturnTypeSpecified CallTo(object fake); |
Code Listing 109: CallTo overload for faking the SUT
Let’s dive into faking the SUT with a redesign of some of the supporting classes involved in sending an email.
Let’s set up a new example with our ISendEmail interface we’ve using throughout the book, but this time, we’ll inject ISendEmail into an abstract base class, which will contain the functionality to actually invoke the call to SendMail.
Our ISendEmail interface:
public interface ISendEmail { void SendMail(string from, string to, string subject, string body); } |
Code Listing 110: The ISendEmail interface
Here is our Customer class:
public class Customer { public string Email { get; set; } } |
Code Listing 111: The Customer class
Let’s add a new abstract class called EmailBase:
public abstract class EmailBase { private readonly ISendEmail emailProvider; protected EmailBase(ISendEmail emailProvider) { this.emailProvider = emailProvider; } protected void SendEmailToCustomers(string subject, string body, List<Customer> customers) { foreach (var customer in customers) { emailProvider.SendMail(GetFromEmailAddress(), customer.Email, subject, body); } } protected virtual string GetFromEmailAddress() { return ConfigurationManager.AppSettings["DefaultFromAddress"]; } } |
Code Listing 112: Abstract class EmailBase
Let’s take a look at what EmailBase is doing:
EmailBase is not really giving us more functionality than the fakes of ISendEmail we’ve been working with for most of the book, except for one thing: it does not required the caller to pass a “From” email address into the SendMail method. In this example, let’s assume that the same “From” address will be used any time we’re sending email to customers.
Finally, here is the ICustomerRepository interface:
public interface ICustomerRepository { List<Customer> GetAllCustomersWithOrderTotalsOfOneHundredOrGreater(); } |
Code Listing 113: The ICustomerRepository interface
GetAllCustomersWithOrderTotalsOfOneHundredOrGreater allows our service class to retrieve a list of customers that have placed one hundred or more orders.
Next, let’s introduce a service class, AdminEmailService:
public class AdminEmailService : EmailBase { private readonly ICustomerRepository customerRepository; public AdminEmailService(ICustomerRepository customerRepository, ISendEmail emailProvider) : base(emailProvider) { this.customerRepository = customerRepository; } public void SendPromotionalEmail(string subject, string body) { var customers = customerRepository .GetAllCustomersWithOrderTotalsOfOneHundredOrGreater(); SendEmailToCustomers(subject, body, customers); } } |
Code Listing 114: The AdminEmailService class
The AdminEmailService class provides an easy way to send promotional emails to customers that have 100 or more orders placed. For example, the email we’re sending could contain a coupon code for discounts because we want to reward our highest purchasing customers. The functionality in this class could be used by the sales department, marketing department, etc. in order to send out these types of emails.
Note that this class inherits from EmailBase, and takes an ICustomerRepository and ISendEmail dependency. But this class does not use the ISendEmail dependency; it passes that dependency into the constructor of its super-class, EmailBase.
Here is the SetUp method of the unit test:
[TestFixture] public class WhenSendingPromotionalEmail { private ISendEmail emailSender; private List<Customer> customers; private const string emailSubject = "EmailSubject"; private const string emailBody = "EmailBody"; private const string theConfiguredFromAddress = "[email protected]"; [SetUp] public void Given() { customers = new List<Customer> { new Customer { Email = "[email protected]" }, new Customer { Email = "[email protected]" } }; var customerRepository = A.Fake<ICustomerRepository>(); A.CallTo(() => customerRepository .GetAllCustomersWithOrderTotalsOfOneHundredOrGreater()).Returns(customers); emailSender = A.Fake<ISendEmail>(); var sut = A.Fake<AdminEmailService>(x => x.WithArgumentsForConstructor(() => new AdminEmailService(customerRepository, emailSender))); A.CallTo(sut).Where(x => x.Method.Name == "GetFromEmailAddress") .WithReturnType<string>().Returns(theConfiguredFromAddress); sut.SendPromotionalEmail(emailSubject, emailBody); } |
Code Listing 115: Setup for unit test of AdminEmailService
Upon first glance, some things look very much the same as we’ve seen from our unit tests written so far in this book. We are still creating a fake of ICustomerRepository and ISendEmail using FakeItEasy, but after that creation and configuration code, things start to look very different.
Faking the SUT introduces us to new API calls we have not seen yet. Let’s explore each of the differences in-depth.
First, let’s take a look at the code we’re using for creating our fake:
var sut = A.Fake<AdminEmailService>(x => x.WithArgumentsForConstructor(() => new AdminEmailService(customerRepository, emailSender))); |
Code Listing 116: Creating a fake of the SUT
Since the AdminEmailService takes two items in its constructor, we need to supply that to the A.Fake<AdminEmailService> call. We do this by passing a lambda to the call that does two things:
These two operations are done by calling WithArgumentsForConstructor, then passing a lambda to that call, which FakeItEasy uses to examine the expression in order to figure out which arguments will be used when creating the fake.
If we look at the signature for the overloaded A.Fake<T> creation, we’ll see the following:
// Summary: // Creates a fake object of the type T. // // Parameters: // options: // A lambda where options for the built fake object can be specified. // // Type parameters: // T: // The type of fake object to create. // // Returns: // A fake object. public static T Fake<T>(Action<FakeItEasy.Creation.IFakeOptionsBuilder<T>> options); |
Code Listing 117: Fake<T> using IFakeOptionsBuilder
Note here that the Action used by Fake<T> uses IFakeOptionsBuilder<T>. Exploring the IFakeOptionsBuilder<T> interface, we see the following:
public interface IFakeOptionsBuilder<T> : IHideObjectMembers { IFakeOptionsBuilder<T> Implements(Type interfaceType); IFakeOptionsBuilder<T> OnFakeCreated(Action<T> action); IFakeOptionsBuilder<T> WithAdditionalAttributes(IEnumerable<Reflection.Emit.CustomAttributeBuilder> customAttributeBuilders); IFakeOptionsBuilder<T> WithArgumentsForConstructor(Expression<Func<T>> constructorCall); IFakeOptionsBuilder<T> WithArgumentsForConstructor(IEnumerable<object> argumentsForConstructor); IFakeOptionsBuilderForWrappers<T> Wrapping(T wrappedInstance); } |
Code Listing 118: IFakeOptionsBuilder interface
There are multiple overloads of WithArgumentsForConstructor. Please feel free to explore the other options you can call when creating a fake with IFakeOptionsBuilder on your own.
Now that we have a fake of our SUT created, we configure it using the following code:
A.CallTo(sut).Where(x => x.Method.Name == "GetFromEmailAddress") .WithReturnType<string>().Returns(theConfiguredFromAddress); |
Code Listing 119: Configuring the faked SUT
Since the only thing going on in AdminEmailService is a call ICustomerRepository to get the customers that have placed 100 or more orders, and since we’ve already taken care of configuring those fakes earlier in the setup code, what we have left to do is configure the protected virtual method, GetFromEmailAddress.
Where(x => x.Method.Name == "GetFromEmailAddress")
This is how we allow FakeItEasy to get a hold of that method to configure it. Note this is done by providing a lambda to the Where call, using that lambda to look up the Method.Name and supplying the name of the method. We also have to use WithReturnType<T> in order to tell FakeItEasy that we expect a string back from this call.
The Where method we’re using here is NOT the Where method provided to us by LINQ. It’s a Where method that is provided to us by a FakeItEasy extension, and it looks like this:
public static class WhereConfigurationExtensions { public static T Where<T>(this IWhereConfiguration<T> configuration, Expression<Func<FakeItEasy.Core.IFakeObjectCall, bool>> predicate); } |
Code Listing 120: The Where extenstion method in FakeItEasy
The Where extension uses an Expression<Func<T, bool>> in order to figure out which method to look up by the provided string.
The configuration code ends with a call to Returns, which allows us to specify a value we expect to be returned from the configured method call.
If any of you at this point are looking at the name of the method being supplied as a string to the configuration and not something that is strongly typed by FakeItEasy, and thinking that looks wrong, in a way you’re right.
When we began this chapter, I stated that if you can avoid faking the SUT, then don’t do it. I also mentioned that many times, when you’re faking the SUT, you’re usually dealing with a class that inherits from a base class, and there most likely will be some behavior in that base class you’ll need to configure.
This his is how we have to deal with this scenario using FakeItEasy. The danger here, of course, is at compile time. If someone changes the name of GetFromEmailAddress method on EmailBase, you’re not going to know at compile time—you’ll only know at runtime.
Which again, is not a big deal, because everyone is running ALL their unit tests before they commit their code, right? Or maybe you have a Continuous Integration (http://en.wikipedia.org/wiki/Continuous_integration) server set up that will kick back failing builds as a result of code that won’t compile, or code where there are any failing unit tests.
In a perfect world, yes… but many of us work in an imperfect world where developers do commit code without running all unit tests, and we don’t have Continuous Integration in place.
If you choose to use FakeItEasy in this way, be aware of these potential problems.
Now that we have our fake created and configured, it’s time to start using it in assertions for our unit tests. If you remember from our test setup, we have two customers that we expect email to be sent to. Here is our first unit test:
[Test] public void SendsTheCorrectAmountOfTimes() { A.CallTo(() => emailSender .SendMail(theConfiguredFromAddress, A<string>._, emailSubject, emailBody)) .MustHaveHappened(Repeated.Exactly.Twice); } |
Code Listing 121: Assertion for the emailSender being called twice
This type of assertion code should look very familiar to you. Note that we’re using A<string>._ shorthand for A<string>.Ignored. Since we set up two customers to be returned from our customerRepository fake, we expect SendMail to be invoked twice. How could we change this test to be better? How about this:
[Test] public void SendsTheCorrectAmountOfTimes() { A.CallTo(() => emailSender .SendMail(theConfiguredFromAddress, A<string>._, emailSubject, emailBody)) .MustHaveHappened(Repeated.Exactly.Times(customers.Count())); } |
Code Listing 122: Using customers.Count() instead of hard coding .twice
We’ve improved the test by getting its count from the customer’s collection that we defined in our unit test setup.
Still, we can do better.
We know it’s important that the email is sent twice, but if two emails were sent to the wrong customer, I think the customers who received those emails would be scratching their heads. Furthermore, we just gave a low-purchasing customer a discount coupon code that they should not be receiving.
Let’s test for the actual email address value:
[Test] public void SendsToCorrectCustomers() { A.CallTo(() => emailSender.SendMail(theConfiguredFromAddress, customers[0].Email, emailSubject, emailBody)).MustHaveHappened(Repeated.Exactly.Once); A.CallTo(() => emailSender.SendMail(theConfiguredFromAddress, customers[1].Email, emailSubject, emailBody)).MustHaveHappened(Repeated.Exactly.Once); } |
Code Listing 123: Testing that we’re sending email to the correct customers
This is testing what should be tested: that the correct email addresses were used when invoking SendMail. But again, it looks like we have those indexes hard-coded for the customers list; we’ve lost the flexibility of the customers.Count change from earlier. Let’s make one more correction.
[Test] public void SendsToCorrectCustomers() { foreach (var customer in customers) A.CallTo(() => emailSender.SendMail(theConfiguredFromAddress, customer.Email, emailSubject, emailBody)) .MustHaveHappened(Repeated.Exactly.Once); } |
Code Listing 124: Interating through customers for each assertion
We’re looping through each customer and asserting that the correct customer’s email address was used. Now if we want to change the number of customers in our setup, we don’t have to change multiple lines of code and mess with indexes in our test.
Similar to how we configured FakeItEasy's behavior when calling the GetFromEmailAddress method in Code Listing 119 in the previous section, it’s possible to call protected property getters/setters as well. Let’s explore a code sample to call a protected abstract property getter.
The interfaces from the previous sample stay the same:
public interface ICustomerRepository { List<Customer> GetAllCustomersWithOrderTotalsOfOneHundredOrGreater(); } |
Code Listing 125: The ICustomerRepository interface
public interface ISendEmail { void SendMail(string from, string to, string subject, string body); } |
Code Listing 126: The ISendEmail interface
We’re going to change the EmailBase class from the previous example:
public abstract class EmailBase { private readonly ISendEmail emailProvider; protected EmailBase(ISendEmail emailProvider) { this.emailProvider = emailProvider; } protected void SendEmailToCustomers(string subject, string body, IEnumerable<Customer> customers) { foreach (var customer in customers) { emailProvider.SendMail(FromEmailAddress, customer.Email, subject, body); } } protected abstract string FromEmailAddress { get; } } |
Code Listing 127: Abstract class EmailBase
In the EmailBase class, instead of having a protected method to get the from email address, we’ve changed the mechanism to retrieve the FromEmailAddress to a protected abstract property getter. Any classes that inherit from this base class will need to provide an implementation of FromEmailAddress. Delegating the implementation of the retrieving the FromEmailAddress to the inheriting class adds a level of flexibility to this class in that it’s not looking up the email address using a hard-coded string via ConfigurationManager that can only be one value for one given configuration.
Note: Declaring protected abstract methods/properties on a base class like this is a GoF Design Pattern called a Template Method(http://www.dofactory.com/net/template-method-design-pattern). One of the more useful design patterns, it allows you combine functionality in an abstract class with the contract enforcement of an interface, and allows that functionality to vary by each class that inherits from the abstract class.
Let’s create a class that will use EmailBase. Sticking with the notion that we want a way to send promotional emails to customers, we’ll create a PromotionalEmailService class:
public class PromotionalEmailService : EmailBase { private readonly ICustomerRepository customerRepository; public PromotionalEmailService(ICustomerRepository customerRepository, ISendEmail emailProvider) : base(emailProvider) { this.customerRepository = customerRepository; } public void SendEmail(string subject, string body) { var customers = customerRepository .GetAllCustomersWithOrderTotalsOfOneHundredOrGreater(); SendEmailToCustomers(subject, body, customers); } protected override string FromEmailAddress { get { return "[email protected]"; } } } |
Code Listing 128: The PromotionalEmailService class
The PromotionalEmailService class inherits from EmailBase, takes ICustomerRepository and ISendEmail dependencies, and passes ISendEmail to the EmailBase’s constructor. This class is also forced to implement the FromEmailAddress getter property via the abstract classes' protected abstraction property declaration.
Let’s write some unit tests for this class to see how to deal with that protected abstract property-getter using FakeItEasy. First, the SetUp method on the test class:
public class WhenSendingPromotionalEmail { private List<Customer> customers; private ISendEmail emailSender; private const string subject = "Subject"; private const string body = "Body"; private const string fromAddress = "fromAddress"; [SetUp] public void Given() { customers = new List<Customer> { new Customer { Email = "[email protected]" }, new Customer { Email = "[email protected]" } }; emailSender = A.Fake<ISendEmail>(); var customerRepository = A.Fake<ICustomerRepository>(); A.CallTo(() => customerRepository .GetAllCustomersWithOrderTotalsOfOneHundredOrGreater()).Returns(customers); var sut = A.Fake<PromotionalEmailService>(x => x.WithArgumentsForConstructor( () => new PromotionalEmailService(customerRepository, emailSender))); A.CallTo(sut).Where(x => x.Method.Name == "get_FromEmailAddress") .WithReturnType<string>().Returns(fromAddress); sut.SendEmail(subject, body); } } |
Code Listing 129: The PromotionalEmailServiceTests unit test setup method
In our Where clause, in order to access the FromEmailAddress property, we append a get_ to the front of the name of the property we want to use in order to tell FakeItEasy what type and value to return. Appending that get_ to the front of the FromEmailAddress property allows FakeItEasy to get access to the property.
The test methods of our unit test class:
[Test] public void SendsTheCorrectAmountOfTimes() { A.CallTo(() => emailSender .SendMail(fromAddress, A<string>._, subject, body)) .MustHaveHappened(Repeated.Exactly.Times(customers.Count())); } [Test] public void SendsToCorrectCustomers() { foreach (var customer in customers) { A.CallTo(() => emailSender .SendMail(fromAddress, customer.Email, subject, body)) .MustHaveHappened(Repeated.Exactly.Once); } } |
Code Listing 130: The test methods for the PromotionalEmailServiceTests class
We have two assertions in our unit test based on our setup. SendsTheCorrectAmountOfTimes makes sure that SendMail is called for the number of customers in our setup. SendsToCorrectCustomers makes sure each email is going to the correct customer.
Now we’ve seen how to call a protected property getter. We call a protected property setter in the same exact way, except instead of prepending get_ to the beginning of the property name, we preppend set_ to the beginning of the property name.
If, in Code Listing 129, the FromEmailAddress was a property setter instead of a property getter, the configuration code would look like this:
A.CallTo(sut).Where(x => x.Method.Name == "set_FromEmailAddress") .Invokes((string a) => fromAddress = a); |
Code Listing 131: What the configuration code would look like if FromEmailAddress was a property setter instead of property getter
In this chapter, we’ve covered why we would need to create a fake of the SUT. We then wrote unit tests for the faked SUT, and finished with a quick look at how to get at protected properties with FakeItEasy. In the next chapter, we’ll take a look at how to use FakeItEasy to test MVC action methods.