单元测试模拟控制器,C# 我需要模拟 HTTPContext 吗?我模拟什么方法?
Unit Test Mock Controller, C# Do I need to Mock HTTPContext? What methods do I mock?
我的任务是为数据库中的一些代码编写单元测试。单元测试必须模拟所有内容,并测试通过和失败的场景。目前我正在使用 NUnit 和 FakeItEasy,我过去使用过 Moq,不介意再次使用它。
控制器
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);
}
客户经理
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;
}
}
这就是我到目前为止的单元测试。我真的不认为我做得对。我觉得我没有正确地模拟对象。
问题:我应该在控制器中模拟和测试哪些方法?
我的测试:(第一个通过,第二个不工作)
[TestFixture]
public class 账户控制器测试
{
//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);
}
}
Question: What methods am I supposed to be mocking and testing within
the controller?
这可能应该是给您设置任务的经理/团队负责人/架构师/高级开发人员的问题:-)
second one isn't working
这个例子在我看来是 AccountController.Search
但你不是在嘲笑 _accountsManager.GetAllWithNameContaining
.
还有Assert.AreSame(mockAccountRequest, returnedAccounts);
,一个是列表,另一个是AccountRequest
。
试试这个:
[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?
要使该测试正常运行,不。接口 ICallerInfoManager
包装对 HttpContext
的调用并将控制器与其隔离,因此它将安全地 运行 通过而不会命中 HttpContext
也就是说,如果您需要测试所有内容,那么是的。您要测试的代码的麻烦部分将是:
public CallerInfo GetFrom(HttpRequest request)
{
return ExtractCallerInfo(request.QueryString);
}
public CallerInfo GetFromHttpContext()
{
return GetFrom(HttpContext.Current.Request);
}
因为对 HttpContext
的硬依赖。
HttpContext
和 HttpRequest
不是那么可嘲笑,但有着密切的关系。正如@Steve G 在评论中提到的那样,这是一个很大的话题。
我的任务是为数据库中的一些代码编写单元测试。单元测试必须模拟所有内容,并测试通过和失败的场景。目前我正在使用 NUnit 和 FakeItEasy,我过去使用过 Moq,不介意再次使用它。
控制器
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);
}
客户经理
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;
}
}
这就是我到目前为止的单元测试。我真的不认为我做得对。我觉得我没有正确地模拟对象。
问题:我应该在控制器中模拟和测试哪些方法?
我的测试:(第一个通过,第二个不工作)
[TestFixture]
public class 账户控制器测试 {
//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);
}
}
Question: What methods am I supposed to be mocking and testing within the controller?
这可能应该是给您设置任务的经理/团队负责人/架构师/高级开发人员的问题:-)
second one isn't working
这个例子在我看来是 AccountController.Search
但你不是在嘲笑 _accountsManager.GetAllWithNameContaining
.
还有Assert.AreSame(mockAccountRequest, returnedAccounts);
,一个是列表,另一个是AccountRequest
。
试试这个:
[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?
要使该测试正常运行,不。接口 ICallerInfoManager
包装对 HttpContext
的调用并将控制器与其隔离,因此它将安全地 运行 通过而不会命中 HttpContext
也就是说,如果您需要测试所有内容,那么是的。您要测试的代码的麻烦部分将是:
public CallerInfo GetFrom(HttpRequest request)
{
return ExtractCallerInfo(request.QueryString);
}
public CallerInfo GetFromHttpContext()
{
return GetFrom(HttpContext.Current.Request);
}
因为对 HttpContext
的硬依赖。
HttpContext
和 HttpRequest
不是那么可嘲笑,但有着密切的关系。正如@Steve G 在评论中提到的那样,这是一个很大的话题。