[英]In C# Unit test how do equivalent of Java's Spy (instead of Mock) to only mock some methods on a class?
[英]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]
公共類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);
}
}
問題:我應該在控制器內模擬和測試哪些方法?
這可能是為您設置任務的經理/團隊負責人/架構師/高級開發人員的問題:-)
第二個不工作
在我看來,這個實例是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);
}
}
我需要模擬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在評論中提到的那樣,這是一個很大的話題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.