Я пишу модульный тест, и одна из проблем, с которыми я сталкиваюсь, - это нулевое исключение в частном классе, который не является частью DI или не инициализируется в параметрах конструктора. Кто-нибудь может мне помочь? Вот мой код. Моя проблема в том, как издеваться над классом PPortalSessionVariables.

Контроллер:

public class EducatorController : BaseController
{
    //Note: PPortalSessionVariables class should NOT be part of IOC
    private readonly IPPortalSessionVariables _ppsessionVariable = new PPortalSessionVariables();
    private readonly IEducatorService _educatorService;

    public EducatorController(IEducatorService educatorService)
    {
        _educatorService = educatorService;
    }

    public ActionResult Index()
    {
        //during test null exception occurs on _ppsessionVariable.CurrentChild.Id
        var model = _educatorService.GetEducatorsForChild(Convert.ToInt64(_ppsessionVariable.CurrentChild.Id));
        return View(model);
    }
}

Тестовый класс:

[TestClass]
public class EducatorControllerTests
{
    public EducatorController CreateController(Mock<IEducatorService> educatorService = null)
    {
        educatorService = educatorService ?? new Mock<IEducatorService>();
        HttpContext.Current = HttpMockHelpers.FakeHttpContextCurrent();
        var controller = new EducatorController(educatorService.Object);
        controller.SetFakeControllerContext("?site=2");
        return controller;
    }

    [TestMethod]
    public void Index_Get_ReturnIndexView()
    {
        var ppsessionVariable = new Mock<IPPortalSessionVariables>();
        var controller = CreateController();
        var child = new ChildModel();
        child.Id = 0;
        ppsessionVariable.Setup(x => x.CurrentChild).Returns(child);
        var result = controller.Index() as ViewResult;
        Assert.IsNotNull(result);
    }
}
0
Jobert Enamno 23 Апр 2014 в 17:03

3 ответа

Лучший ответ

Не понимаю, почему вы просто не используете его как любую другую зависимость, внедряя его через IoC. Что касается работы Moq, вы должны издеваться над этим классом, но никогда не сможете установить этот объект, возможно, обходным путем является создание установщика для этого свойства и вызов свойства в вашем тесте, передавая фиктивный объект.

ПедагогКонтроллер

public void SetPortalSession(IPPortalSessionVariables portal)
{
   _ppsessionVariable = portal;
}

ПедагогКонтроллерТесты

 [TestMethod]
 public void Index_Get_ReturnIndexView()
 {
     var ppsessionVariable = new Mock<IPPortalSessionVariables>();
     var controller = CreateController();
     controller.SetPortalSession(ppsessionVariable.object);
     var child = new ChildModel();
     child.Id = 0;
     ppsessionVariable.Setup(x => x.CurrentChild).Returns(child);
     var result = controller.Index() as ViewResult;
     Assert.IsNotNull(result);
  }
1
mart 23 Апр 2014 в 14:05

Есть две вещи, которые действительно вызывают у вас эту головную боль:

  1. Тот факт, что _ppSessionVariable является частным и не подвергается воздействию внешнего мира
  2. Предполагается, что IPPortalSessionVariables.CurrentChild никогда не должен возвращать null для всех реализаций интерфейса.

Если вы обратитесь к одному из этих пунктов, ваша проблема исчезнет.

  1. Предоставьте общедоступный установщик, чтобы разрешить модульному тесту явно устанавливать _ppsessionVariable для фиктивного объекта. Что-то вроде:

    public void SetSessionVariable(IPPortalSessionVariables ppsessionVariable)
    {
        _ppsessionVariable = ppsessionVariable;
    }
    
  2. Выполните рефакторинг вашего кода, чтобы _ppsessionVariable.CurrentChild не возвращал null.

    Самым простым, вероятно, было бы инициализировать CurrentChild как Null Объект в конструкторе PPortalSessionVariables.

2
Lilshieste 23 Апр 2014 в 15:08

Ваш EducatorController явно очень тесно связан с PPortalSessionVariables. Пока у вас не будет new PPortalSessionVariables() в модуле контроллера, тестирование изолированно будет невозможно. Чтобы исправить это, убедитесь, что EducatorController зависит от абстракции IPPortalSessionVariables, а не от конкретной реализации.

Как уже предлагали другие, подумайте о создании общедоступного установщика для IPPortalSessionVariables или продолжайте внедрение конструктора.

2
Amol 24 Апр 2014 в 04:23