Reputation: 759
I am tasked with writting unit Tests for some code we have in our Database. The Unit Tests must Mock everything, and test for both passing and failed scenarios. Currently I am using NUnit and FakeItEasy, I have used Moq in the past and don't mind using it again.
Controller
public class AccountController : BaseController
{
private readonly IAccountsManager _accountsManager;
private readonly ICallerInfoManager _callerInfoManager;
public AccountController(IAccountsManager accountsManager, ICallerInfoManager callerInfoManager)
: base(callerInfoManager)
{
_accountsManager = accountsManager;
_callerInfoManager = callerInfoManager;
}
[HttpGet]
[ActionName("GetAll")]
public List<Account> Get()
{
var context = _callerInfoManager.GetFromHttpContext();
return _accountsManager.GetAll(context.SiteLocationCode);
}
[HttpPost]
[ActionName("Search")]
public List<Account> Search(AccountRequest request)
{
var context = _callerInfoManager.GetFromHttpContext();
return _accountsManager.GetAllWithNameContaining(request.SearchTerm, context.SiteLocationCode);
}
}
CallerInfoManager
public class CallerInfoManager : ICallerInfoManager
{
private readonly IContactContextManager _contactContextManager;
private const string ContactIdKey = "c";
private const string SafeIdKey = "sa";
private const string SiteLocationCode = "s";
public CallerInfoManager(IContactContextManager contactContextManager)
{
_contactContextManager = contactContextManager;
}
public CallerInfo GetFrom(HttpRequest request)
{
return ExtractCallerInfo(request.QueryString);
}
public CallerInfo GetFromHttpContext()
{
return GetFrom(HttpContext.Current.Request);
}
AccountManager
public class AccountsManager : IAccountsManager
{
private readonly IAccountRepository _accountRepository;
public AccountsManager(IAccountRepository accountRepository)
{
_accountRepository = accountRepository;
}
public List<Account> GetAll(string siteLocationCode)
{
return _accountRepository.GetAll(siteLocationCode);
}
public List<Account> GetAllWithNameContaining(string term, string siteLocationCode)
{
return _accountRepository.Search(term, siteLocationCode);
}
public Account Add(Account account)
{
_accountRepository.Add(account);
return account;
}
}
This is what I have so far for my Unit tests. I really dont think I am doing it right. I feel like I am not properly mocking the objects.
Question: What methods am I supposed to be mocking and testing within the controller?
My Tests: (First one passes, second one isn't working)
[TestFixture]
public class AccountControllerTests {
//Tests that all accounts where returned
[Test]
public void GetAllAccounts_ReturnAllAccounts()
{
//Arrange
var mockAccountsManager = A.Fake<IAccountsManager>();
var mockCallerInfoManager = A.Fake<ICallerInfoManager>();
using (var accountsController = new AccountController(mockAccountsManager, mockCallerInfoManager))
{
//Act
List<Account> accounts = accountsController.Get();
//Assert
A.CallTo(() => mockCallerInfoManager.GetFromHttpContext()).MustHaveHappened();
Assert.AreNotEqual(null, accounts);
}
}
//Tests that the proper search parameter was returned
[Test]
public void SearchforAccount_ReturnSearchAccount()
{
//Arrange
var mockAccountsManager = A.Fake<IAccountsManager>();
var mockCallerInfoManager = A.Fake<ICallerInfoManager>();
Account searchAccountEntity = new Account
{
Id = 01,
CompanyName = "google"
};
//Define search parameter
AccountRequest mockAccountRequest = new AccountRequest
{
SearchTerm = "google"
};
using (var accountsController = new AccountController(mockAccountsManager, mockCallerInfoManager))
{
//Act
List<Account> returnedAccounts = accountsController.Search(mockAccountRequest);
mockAccountsManager.GetAllWithNameContaining("universal", "test");
//Assert
Assert.AreSame(mockAccountRequest, returnedAccounts);
}
}
Upvotes: 1
Views: 739
Reputation: 18649
Question: What methods am I supposed to be mocking and testing within the controller?
This should probably be a question for the manager / team lead / architect / senior developer who set you the task :-)
second one isn't working
Is this instance the sut seems to me to be AccountController.Search
but you're not mocking _accountsManager.GetAllWithNameContaining
.
Also with Assert.AreSame(mockAccountRequest, returnedAccounts);
one is a list, the other is an AccountRequest
.
Try this:
[Test]
public void SearchforAccount_ReturnSearchAccount()
{
//Arrange
var mockAccountsManager = A.Fake<IAccountsManager>();
var mockCallerInfoManager = A.Fake<ICallerInfoManager>();
const string SearchTerm = "google"; // Use the passed in parameter in the CallTo setup
//Define search parameter
AccountRequest mockAccountRequest = new AccountRequest
{
SearchTerm = SearchTerm
};
List<Account> expected = new List<Account> { new Account() }; // What we expect to get back
A.CallTo(() => mockAccountsManager.GetAllWithNameContaining(SearchTerm, A<string>.Ignored)).Returns(expected); // mock the call made in the controller
using (var accountsController = new AccountController2(mockAccountsManager, mockCallerInfoManager))
{
//Act
List<Account> returnedAccounts = accountsController.Search(mockAccountRequest);
//Assert
Assert.AreSame(expected, returnedAccounts);
}
}
Do I need to Mock HttpContext?
To get that test working, no. The interface ICallerInfoManager
wraps the call to HttpContext
and isolates the controller from it, so it will safely run through without hitting HttpContext
That said, if you need to test everything then yes. Your trouble part of the code to test will be:
public CallerInfo GetFrom(HttpRequest request)
{
return ExtractCallerInfo(request.QueryString);
}
public CallerInfo GetFromHttpContext()
{
return GetFrom(HttpContext.Current.Request);
}
Because of the hard dependency to HttpContext
.
HttpContext
and HttpRequest
are not that mockable, but have close relations which is. And as @Steve G alluded to in the comments that's quite a big topic.
Upvotes: 1