Как могут Вы к Модульному тесту Ваши контроллеры без контейнера МОК?

Это сокращение в одну строку для оператора if-else. Он называется условным оператором. 1

Вот пример кода, который можно сократить с помощью условного оператора:

if(userIsYoungerThan21) {
  serveGrapeJuice();
}
else {
  serveWine();
}

Это можно сократить с помощью ?: примерно так:

userIsYoungerThan21 ? serveGrapeJuice() : serveWine();

В Javascript условный оператор может вычислять выражение, а не просто выражение:

var userType = userIsYoungerThan18 ? "Minor" : "Adult";
serveDrink(userIsYoungerThan21 ? "Grape Juice" : "Wine");

Они могут даже быть связаны:

userIsYoungerThan4 ? serveMilk() : userIsYoungerThan21 ? serveGrapeJuice() : serveWine();

Будьте осторожны, иначе у вас получится замысловатый код, подобный этому:

var k = a ? (b ? (c ? d : e) : (d ? e : f)) : f ? (g ? h : i) : j;

1 Часто называют «троичным оператором, «но на самом деле это просто троичный оператор [оператор, принимающий три операнда]. Это единственный JavaScript, который есть на данный момент.

6
задан 25 June 2009 в 02:36
поделиться

4 ответа

Isn't it possible to keep the direct instantiation of the field and also provide the setter? In this case you'd only be calling the setter during unit testing. Something like this:

public class QuestionsController : ControllerBase
{
    private IQuestionsRepository _repository = new SqlQuestionsRepository();

    // Really only called during unit testing...
    public QuestionsController(IQuestionsRepository repository)
    {
        _repository = repository;
    }
}

I'm not too familiar with .NET but as a side note in Java this is a common way to refactor existing code to improve the testability. I.E., if you have classes that are already in use and need to modify them so as to improve code coverage without breaking existing functionality.

Our team has done this before, and usually we set the visibility of the setter to package-private and keep the package of the test class the same so that it can call the setter.

2
ответ дан 17 December 2019 в 04:51
поделиться

У вас может быть конструктор по умолчанию с вашим контроллером, который будет иметь какое-то поведение по умолчанию.

Что-то вроде ...

public QuestionsController()
    : this(new QuestionsRepository())
{
}

Таким образом по умолчанию, когда фабрика контроллеров создает новый экземпляр контроллера он будет использовать поведение конструктора по умолчанию. Затем в своих модульных тестах вы можете использовать фреймворк для имитации, чтобы передать имитацию в другой конструктор.

2
ответ дан 17 December 2019 в 04:51
поделиться

Один из вариантов - использовать подделки.

public class FakeQuestionsRepository : IQuestionsRepository {
    public FakeQuestionsRepository() { } //simple constructor
    //implement the interface, without going to the database
}

[TestFixture] public class QuestionsControllerTest {
    [Test] public void should_be_able_to_instantiate_the_controller() {
        //setup the scenario
        var repository = new FakeQuestionsRepository();
        var controller = new QuestionsController(repository);
        //assert some things on the controller
    }
}

Другой вариант - использовать макеты и фреймворк имитации, который может автоматически генерировать эти макеты на лету.

[TestFixture] public class QuestionsControllerTest {
    [Test] public void should_be_able_to_instantiate_the_controller() {
        //setup the scenario
        var repositoryMock = new Moq.Mock<IQuestionsRepository>();
        repositoryMock
            .SetupGet(o => o.FirstQuestion)
            .Returns(new Question { X = 10 });
        //repositoryMock.Object is of type IQuestionsRepository:
        var controller = new QuestionsController(repositoryMock.Object);
        //assert some things on the controller
    }
}

Относительно того, где находятся все объекты. построить. В модульном тесте вы настраиваете только минимальный набор объектов: реальный объект, который находится в стадии тестирования, и некоторые поддельные или фиктивные зависимости, которые требуются для реального тестируемого объекта. Например, реальный тестируемый объект является экземпляром QuestionsController - он зависит от IQuestionsRepository , поэтому мы даем ему либо поддельный IQuestionsRepository , как в первый пример или макет IQuestionsRepository , как во втором примере.

В реальной системе, однако, вы настраиваете весь контейнер на самом верхнем уровне программного обеспечения. В веб-приложении

1
ответ дан 17 December 2019 в 04:51
поделиться

Я немного расширяю ответ Питера.

В приложениях с большим количеством типов сущностей контроллер нередко требует ссылок на несколько репозиториев, служб и т. Д. Мне утомительно вручную передавать все эти зависимости в моем тестовом коде (тем более, что данный тест может включать только один или два из них). В этих сценариях я предпочитаю вводить IOC в стиле установщика вместо внедрения конструктора. Я использую этот шаблон:

public class QuestionsController : ControllerBase
{
    private IQuestionsRepository Repository 
    {
        get { return _repo ?? (_repo = IoC.GetInstance<IQuestionsRepository>()); }
        set { _repo = value; }
    }
    private IQuestionsRepository _repo;

    // Don't need anything fancy in the ctor
    public QuestionsController()
    {
    }
}

Замените IoC.GetInstance <> любым синтаксисом, который использует ваша конкретная структура IOC.

При производственном использовании ничего не вызывает установщика свойств, поэтому при первом вызове получателя контроллер вызовет вашу структуру IOC, получит экземпляр и сохранит его.

В тесте вам просто нужно вызвать установщик перед вызовом любых методов контроллера:

var controller = new QuestionsController { 
    Repository = MakeANewMockHoweverYouNormallyDo(...); 
}

Преимущества этого подхода, ИМХО:

  1. По-прежнему использует преимущества IOC в производстве.
  2. Проще создавать контроллеры вручную во время тестирования. Вам нужно только инициализировать зависимости, которые фактически будет использовать ваш тест.
  3. Возможно создание конфигураций IOC для конкретных тестов, если вы не хотите вручную настраивать общие зависимости.
0
ответ дан 17 December 2019 в 04:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: