'Classist Unit Testing - Avoiding Mocks
I am trying to follow the Classist approach for Unit Testing. I try to only mock external dependencies (external API, file system, etc...). I try to separate data access code (EF Core) from core domain classes, allowing me to test those core classes without those dependencies.
In the following class:
using System;
using System.Threading.Tasks;
using Cornerstone.Services;
using MediatR;
using Cornerstone.Entities.Cornerstone.Actions.LDAP;
using Cornerstone.Entities.Cornerstone.Actions;
namespace Cornerstone.Features.Actions.ActionExecuters
{
public class AddUserActionExecuter : IActionExecuter
{
private readonly LdapService ldapService;
private readonly AddUserAction action;
private readonly IMediator mediator;
public AddUserActionExecuter(LdapService ldapService, AddUserAction action, IMediator mediator)
{
this.ldapService = ldapService ?? throw new ArgumentNullException(nameof(ldapService));
this.action = action ?? throw new ArgumentNullException(nameof(action));
this.mediator = mediator;
}
public async Task<bool> CanExecute()
{
var sourceContact = await mediator.Send(new GetContactForActionQuery(action));
return !string.IsNullOrWhiteSpace(action.SamAccountName)
&& !string.IsNullOrWhiteSpace(action.Email)
&& !string.IsNullOrWhiteSpace(sourceContact.FirstName)
&& !string.IsNullOrWhiteSpace(sourceContact.Surname)
&& !string.IsNullOrWhiteSpace(action.Ou)
&& action.Groups.Count > 0;
}
public async Task<ExecutionResult> Execute()
{
var sourceContact = await mediator.Send(new GetContactForActionQuery(action));
ldapService.CreateUserAccount(action.Ou, action.SamAccountName, action.Password, action.UniqueCN, action.Email, sourceContact.FirstName, sourceContact.Surname, action.Email);
ldapService.AddUserToGroups(action.SamAccountName, action.Groups.ToArray());
return new ExecutionResult { Successful = true };
}
}
}
you can see that I am using MediatR to send queries. Using MediatR, I am fetching a Contact that corresponds to a SourceContactId property on the AddUserAction class.
If I want to unit test the logic in the CanExecute method, I can see two choices:
- Mock the MediatR handler and make it return a contact I prepared
- Create a new class like
AddAdUserActionExecuter_Helperthat has a methodbool CheckCanExecute(AddUserAction action, Contact contact)and move the logic there, then I would call this from the originalCanExecuteand unit test only the new method which now has no dependency on MediatR.
My question is: in number 2 which may be the option more inline with my design choices, given that there is only one user for this introduced method, doesn't it seem like we're adding a new class and exposing its method just for the sake of testing?
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
