单元测试模拟控制器,C#我需要模拟HTTPContext吗?我会嘲笑哪些方法?

时间:2016-01-22 17:18:13

标签: c# unit-testing mocking nunit fakeiteasy

我的任务是编写单元测试我们在数据库中的一些代码。单元测试必须模拟一切,并测试通过和失败的情况。目前我正在使用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);
    }

的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;
    }
}

这是我目前为我的单元测试所做的。我真的不认为我做得对。我觉得我没有正确地嘲笑这些物体。

问题:我应该在控制器中嘲笑和测试哪些方法?

我的测试:(第一个通过,第二个无效)

    [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);

        }
    }

1 个答案:

答案 0 :(得分:1)

  

问题:我应该采用哪些方法进行模拟和测试   控制器?

对于为您设定任务的经理/团队负责人/架构师/高级开发人员来说,这应该是一个问题: - )

  

第二个不起作用

这个实例在我看来是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的依赖性很强。

HttpContextHttpRequest不是那么可以模仿,而是有密切的关系。正如@Steve G在评论中所提到的那样,这是一个非常重要的话题。