I’ve been working pretty flat out recently trying to resurrect the effects of a large API change on our Excel Add-in. We’ve changed the signature, return types and behaviour of API in a more intuitive way. This means that I’ve had to refactor all client code that expected the old way of things. This in itself actually was not the hard part, the hard part was actually fixing our tests.

One of the ways we ensure that our functionality is doing what we expect it to do, is that we test it by assessing before and after states of certain pieces of code. This ensures that that functionality hasn’t changed those expectations. We use Moq to do this. So basically we’ve got test coverage for most of our functionality, and these things have an absolute cadenza when these types of API changes happen.

The most interesting problem I had recently was around the mocking nature of these tests. A basic testing principle described above is further complicated when your functionality that you are testing does something behind the scenes that relies on being ‘online’ or ‘in production’ or connecting to a database somewhere. These are all things that you don’t want to have when you’re testing some piece of functionality(which has this dependency). So we can ‘mock out’ that piece of work, and continue to test everything else.

Mocking will allow one to have a say in what happens when that dependency(say fetching data from an API or database) is reached. In most cases you’ll tell it not to go and fetch the data, but rather you’ll instruct it to think its going to fetch the data and give it ‘mock’ data and it’ll use that moving forward, thinking that it had happily gone and fetch the data live from the database/internet.

The data that you faked is used to it is just to get by that external dependency(say to call out to the internet/database), to get past that point in the functionality, then the mocked data is used throughout the functionality under test. We provide this fake data before the test and ensure that our expectations about the test and perhaps how its affected that test data are still in place after the functionality run.

So the particular problem I’ve recently had was to resolve an issue whereyby I’d need to Mock out an API request but its a API request thats quite odd. It contains a function as a parameter. I need not to entirely mock out the entire function, but to do so but still have the function parameter run and me mock that. Huh? – how bizarre. Have a look:

This is the call to mock, or at least its signature - see the Action<IMeta> call as a parameter. I dont want to mock that out completely...

public delegate void GetPortfoliocallSignature(
Scope scope,
Code portfolioId, 
DateTimeOffset? effectiveDate, 
AsAtPredicate asAt, 
Action<IMeta> getMeta);

And this is how it gets called internally, within the test:

IMeta portfolioMeta = null;

var results = PortfoliosHttpClient.ListPortfolios(
ParamUtils.GetDate(effectiveDate).ToDateTimeOffSet(), ParamUtils.GetDate(asAt).ToAsAtPredicate(),
getMeta: meta => portfolioMeta = meta);

This basically is a call that goes a fetches some data from the API(ListPortfolios), now i dont want that to go and do that when I’m testing, so I’ll mock this call to return/fetch some fake data. Problem is that there a Action<data> parameter which is responsible for setting a variable, prior to this call. I still need that variable to be set by this call but I’m mocking the entire function out, effectively removing the effects of this call entirely during test(even the Action paramter which would normally be run) – and replacing it with a mock call.

This unfortunately causes that parameter never to be evaluated and my variable(portfolioMeta) is never set – its always null. I’d like to set it to fake data too so it sets my variable and also the effects of the entire function (ListPortfolio) need to be mocked also. This is how it can be done:

 var mockPortfoliosClient = new Mock<IPortfoliosClient>(MockBehavior.Strict);
mockPortfoliosClient.Setup(x => x.GetPortfolio(
.Callback(new GetPortfoliocallSignature((scope, id, date, at, meta) => meta(TestData.Meta.DummyMeta)))
.Returns(ResponseHelper.CreatePortfolioResponse(portfolio, details, new PortfolioPropertiesDto{Properties = properties}));

Mock out the main ListPortfolios function, but get a call when you do, and then you can influence the mocking of that call, including setting the Action parameter to provide always mocked data via the call to:

=> meta(TestData.Meta.DummyMeta))

Which basically says, I'll provide a mocked version of the action parameter function, so anyone calling the overall function (our test) will have a my mock Action function run and in this case, that mock function will  provide mocked data to the outside world instead of not running at all. Its a fairly complicated scenario to explain...but I'll try.

This means that when the full mocked call is about to be mocked, it allows a call back to be called which I subscribe to, and this allows me to intercept the mocking out of the call and more importantly influence the invocation, including mocking the parameter with a version of Action<data>. I can do this and  always returns mock data and so always sets the variable to this mock data over and above mocking this entire API call.

You can do this with Moq's .Callback() function which as explained allows me to influence the call to Action<IMeta> meta and at the same time, then mock out the call to GetPortfolioFolio entirely and mock its response.

That’s pretty nifty.

Comments powered by CComment