Structuring large ASP.NET Core projects for testing and readability


This is a continuation of the post Testing an API In Memory in ASP.NET Core where I described in detail how to test an ASP.NET Core API end-to-end in an isolated, repeatable fashion. This is a shorter post that discusses an approach to structuring your project that should make it easier to test and develop.

Oh and there are lots of code samples again!

Where we left off

In my previous post I described how to get a truly isolated in-memory instance of a ASP.NET Core API configured in a test harness to perform repeatable tests. We created an InMemoryStartup class (for configuring the site for testing) and an InMemoryApi class (for encapsulating Test Doubles and setting up the API). I did not go into detail about the content of either of the Start up classes which is what I intend to address here.

Much of the complexity from this kind of testing derives from having to maintain two configuration classes and keeping them in sync correctly. It is all too easy for strange bugs to creep in and go unnoticed when differences are not correctly replicated.

The solution to this is actually quite straightforward which is to create shared configuration classes that can be specialised for your in-memory testing situation. My solution involves creating two configuration classes, one for each of the two methods that are implemented by convention in your regular Startup.cs and the two methods of the IStartup interface. These are:

  • WebAppConfigurator - for the Configure method of Startup
  • ServiceCollectionInstallerRunner - for the ConfigureServices method of Startup

Both of these classes will have in-memory versions of themselves implemented as extension classes - we will come on to this later.


[Read More]

Testing an API In Memory in ASP.NET Core


This is long post that describes how to setup an in-memory test harness for testing an entire ASP.NET Core API with lots of code examples.

Testing and broccoli

Unit testing, like broccoli, is something we all know we should do, but actually we just want to tuck into the meat and potatoes of production code. One reason you might resist writing unit tests is that you are writing an API which is mostly a CRUD layer over a database (where most of the code is right-to-left copying from a DTO to an API response), or you are writing framework plugins for which you just can’t write meaningful tests (for instance ActionFilters or Binder).

Well I understand, I’ve been in the same situation, but I have a way of dealing with this problem. What I prefer to do is test at the level of http all the way through the API to the database. But wait, you may cry, that’s not a unit test! Well yes you have a point there, I’m touching lots of different classes when I test like this. I would argue however that the word “unit” is a bit ambiguous; my definition of unit is not ‘a single class’.

I prefer to classify tests as either Isolated, Integration, or End-to-End. When I say isolated, what I mean is that the test can be run without worrying about external dependencies, whether they are your databases or an external API or other system. This means you can test anything from a single class up to the whole API, reliably and repeatably. Integration tests then focus on integrations with your database, external APIs etc. These tests are simple and limited in scope so when they break your integration code is broken or the system is down. End-to-End tests end up being more akin to smoke tests or sanity tests and any break in these should be reflected in your Isolated and Integration tests.

Given these definitions let’s look at how you can test your API end-to-end in an isolated fashion. Or put another way, let’s cook that broccoli in butter and chilli and season with salt, pepper and a little grated parmesan (you’re welcome!)

In order to test an ASP.NET Core application we need to be able to spin up our whole application in a test harness (i.e. your unit test/test fixture). Microsoft provide a NuGet package that lets us do just that; Microsoft.AspNetCore.TestHost contains a class called TestServer. Once you create an instance of the TestServer you can get an instance of a HttpClient with which you can then make http calls to your API.

Creating a TestServer instance

To create an instance of the TestServer you need to supply its constructor with an instance of a WebHostBuilder. The easiest way to create a WebHostBuilder is in the same manner as you would when you are building your IWebHost implementation to run your site with Kestrel.

[Read More]

Starting your career as a software developer

A couple of years ago I was asked to give a talk to programming undergraduates at Kings College, London. I wrote up the session as a blog post and added it to my personal website, where it has received thousands one or two hits since.

Reading it back this week I was pleasantly surprised how relevant and useful it still is, and as we are currently hiring engineers at the start of their career it is worth resharing here.

Getting that first job

Whilst I can still remember the interview for my first job, I have greater insight these days from interviewing developers, and I have personally recruited, managed and mentored a number of junior engineers at the beginning of their careers. The next sections talk about our hiring process at OpenTable and within this framework here’s how you’d get us to give you a job.

The CV

The CV is not as crucial as you might think. Get the basics right – no typos and a neat layout – but don’t cram it full of everything you’ve ever done, just enough to whet our appetite. A single page is usually best (no more than two).

The most important thing for a job as a developer is to show that you love writing code. Nothing conveys this passion better than sites/plugins/projects/online courses that you have worked on, particularly outside of your employment. Even better, provide links to repositories, websites, blogs or Q&A sites to show your work and genuine interest.

Dare I say it, but your exams results do not really matter to us. Passion, backed up with examples of work will grab our attention, with that hard-earned first or 2:1 counting only as a tie-breaker.

The code test

If we like your CV we’ll ring you for a quick chat, and then ask you to complete a test - either at our office or in your own time. The coding test will vary from role-to-role but will need skills that will be required in the job. If you can’t do the test at all then this isn’t the right role for you, but if you can do part of it then give it a go as it will give us things to talk about in the next stage of the interview.

[Read More]

Monads explained by a imperative programmer - with examples

A monad is any type construct that follows a specific pattern; it works in the same way as other design patterns. The .NET ApplicationContext is a singleton in the same way that Array is a Monad. Something being a monad does not define its purpose; in the same way that a class can implement many interfaces, a monadic type can also conform to many patterns to increase its usefulness.

Monads are hard to get our heads around because they are very generic. They are defined by having two methods: the bind method (also commonly called fmap), and the unit method (also commonly known as pure or from).

A bind/fmap method.

The fmap method follows this signature:

// Given a monadic type TMonad with value type V1,
// and a method that takes a value of type V1 and
// returns the same monadic type TMonad but with
// a value type of V2, produce a monadic type
// TMonad with value V2.
function (TMonad<V1> m, Func<V1, TMonad<V2>> f) => TMonad<V2>

A quick breakdown of the method signature in plain english: given a monadic type TMonad with value type V1, followed by a method that takes a value of type V1 and returns the same monadic type TMonad but with a value type of V2, produce a monadic type TMonad with value V2.

From the signature, it appears that we should give the value V1 from the first monad to the function f and simply return the TMonad from that call. The ability to control the usage of that function and the ability to intercept the return value is where it gets interesting.

The resulting monad will usually be a composition of the original monad, and the new monad produced by f. That means the “state” held by the two monads are merged and the specifics of how is up to the developer.

The monadic type TMonad cannot change after a call to f; a Maybe monad cannot change to a State monad, but this also means that a Maybe monad can never read the value of a State monad by being bound to it. This is something I understood later when I started to question how to use different monads together.

The value type V1 is free to change as a result of calling f. This is why we denote the final result as TMonad<V2>; this doesn’t prevent the value staying the same, in the same way that in a program, x can equal 1 and y can also equal 1, V1 could represent a boolean and V2 could also represent a boolean.

A unit/pure/from method

[Read More]

Circuit Breakers and Application Resilience

For most people circuit breakers are a concept that belongs in the world of electricity. They are usually a box of fuses under the stairs that prevents the tangle of extension cords from turning into an unexpected open fireplace behind the TV. But the concept of a circuit breaker is something that we can apply to software and software services.

Martin Fowler described a software circuit breaker as follows:

“… a protected function call in a circuit breaker object, which monitors for failures. Once the failures reach a certain threshold, the circuit breaker trips, and all further calls to the circuit breaker return with an error, without the protected call being made at all”


OpenTable runs on many microservices that depend on one another to deliver the OpenTable site. These services can have dependencies on data stores such as MongoDB and Elastic Search as well as services such as RabbitMQ and Redis. Sometimes these dependencies can have performance or availability issues; such as when somebody accidentally drops an index on a collection in Mongo.

This actually happened, your author accidentally dropped a critical index while working with a DB synchronization tool which resulted in downtime. Hence this article.

When this happens calls to dependencies may fail or take a long time to complete which then causes the dependent service to behave in the same way. Other upstream services can also suffer the same problem. This can be described as a cascading failure.

Ideally what we would like to happen at this point is for our service to recognize what is happening, fail gracefully, and stop calling the service that already can’t keep up with the load placed upon it. (As well as alerting us to the problem). This is where a software circuit breaker can help us.

Polly to the rescue

[Read More]

Hosting external events

This June, OpenTable hosted the London Machine Learning Study Group to great success. We provided the food, drinks, and space for an extremely talented speaker and over 100 RSVPs. It was also my first experience hosting an external meetup at OpenTable - and I learned a lot!

My Experience

OpenTable has frequently hosted meetups in our office such as Web Platform London and WEBdeLDN. However, acting as an event host was a complete unknown for me, so leading up to the machine learning event, I made a point of sitting down with someone who had organised one before.

We documented the key steps in setting up an external event, and then published what we’d discussed on our internal wiki so as to avoid siloing useful information for future use. Following the steps documented in the wiki proved invaluable in reducing my stress on the day.

After our last event we also looked back on how we’d done the last few events.


Following our last meetup, we held a retrospective as, along with the London Machine Learning Study Group, we have had a recent spate of meetups at OpenTable. This was extremely useful to underline our shared experiences as well as the considerations we want to make for our next external event. Here are a few areas we will look to improve.

Push social media more

We want the largest number of people to know about these events ahead of time, which means not just relying on one platform. Instead we aim to advertise our meetups on all channels available to us to get as diverse an audience as possible. We will tweet about our events more via @OpenTableTechUK and we will use this blog to advertise upcoming events.

A lot of people don’t turn up

[Read More]

Pragmatic Testing with GraphQL

We’ve been using GraphQL at OpenTable for a little over half a year now. I won’t go into detail as to why we started using it, but suffice to say, we really enjoyed creating our very first GraphQL endpoint. It eased a lot of the inconsistencies that we were experiencing with some of our REST-ful services.

This post assumes you have some experience building a GraphQL endpoint. For those of who you aren’t familiar with it, it feels a lot like having a querying language via an HTTP endpoint. If you want to try it for yourself, I recommend GitHub’s endpoint. To get started with GraphQL, the official documentation is a perfect place.

The Problem

Now, let’s get back to writing tests for an endpoint. When we were creating our first endpoint, we started facing regression testing problems while expanding our schema. It seemed our existing testing methods were ill-equipped to handle it.

Finding a good solution to this is important because I’ve had such a love–hate affair with testing. All tests are not created equal and a naive developer would say, “write a test in case something changes”. This certainly isn’t a good measure. I’ve also found that just attempting to write tests immediately without forethought can be a costly distraction if you grow your codebase.

The Approach

So we took a step back and looked at the code we were writing. Most of the connectors we wrote were fairly anemic. We didn’t have much logic for our API nor did we want any. We could have written unit tests for each parts of the schema but mocking portions of the system seemed more work than it was worth.

So where did we start? I personally enjoy the outside-in approach and started writing a few acceptance tests. So, we wrote a test for each query in the schema that we had. It would fire an HTTP request and expect a 200 status code and have no errors in the resulting JSON body. Thanks to GraphQL most errors are handily reported using this mechanism so we would be able to make a decent impact using little work.

As you can see, we found that this would be good enough at the time but eventually found that it would not scale very well. If you forget to update one of these queries, you could leave out a major section out accidentally. Being a big fan of automation, we wondered how we could scale this out.

[Read More]