I am trying to write some unit tests. The application has a number of external API calls that I would like to mock using NSubstitute. The issue is these calls use service objects that need to be instantiated in the function and can't be passed in the constructor after substitution.
For example, in the code below I am adding an account to Quickbooks:
public async Task AddQuickbooksAsync(int accountId)
{
var qbChannel = await GetQuickbooksChannel();
var account = await GetAsync(accountId);
var quickbooksBO = new QuickbooksBO(qbChannel);
quickbooksBO.AddAccount(account);
quickbooksBO.UpdateRefreshedTokens(qbChannel);
await context.SaveChangesAsync();
}
I want to mock the following function call using NSubstitute, but couldn't figure out how:
var quickbooksBO = new QuickbooksBO(qbChannel);
quickbooksBO.AddAccount(account);
How can I do this?
You cannot mock a local variable. You can create a virtual method which will return QuickbooksBO
and substitute it.
public async Task AddQuickbooksAsync(int accountId)
{
var qbChannel = await GetQuickbooksChannel();
var account = await GetAsync(accountId);
var quickbooksBO = GetQbBO(qbChannel);
quickbooksBO.AddAccount(account);
quickbooksBO.UpdateRefreshedTokens(qbChannel);
await context.SaveChangesAsync();
}
public virtual QuickbooksBO GetQbBO(Channel qbChannel)
{
return new QuickBooks(qbChannel);
}
After that you can substitute it in your service:
var s = Substitute.ForPartsOf<Service>();
s.GetQbBO(default).ReturnsForAnyArgs(substituteForQbBO);
You will need to figure out what parts of QuickBooksBO you want to mock. Usually such dependencies should be interfaces, without interfaces unit-testing is quite limited.
If QuickbooksBO
methods are virtual you can do something like this to get your substituteForQbBO
:
var substituteForQbBO = Substitute.ForPartsOf<QuickbooksBO>();
substituteForQbBO.WhenForAnyArgs(x => x.AddAccount(default)).DoNotCallBase();
substituteForQbBO.WhenForAnyArgs(x => x.UpdateRefreshedTokens(default)).DoNotCallBase();