'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:

  1. Mock the MediatR handler and make it return a contact I prepared
  2. Create a new class like AddAdUserActionExecuter_Helper that has a method bool CheckCanExecute(AddUserAction action, Contact contact) and move the logic there, then I would call this from the original CanExecute and 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