Как замкнуть вызов метода установки свойств в Moq - PullRequest
0 голосов
/ 17 сентября 2018

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

Я знаю, что могу переместить эту логику в метод, а затем вместо этого смоделировать этот новый метод, но эта проблема сделала меня любопытным, и я немного покопался. Результаты моего исследования представлены в классе FooTests ниже, один из которых использует SetupProperty, но заставляет меня чувствовать, что это не то, для чего этот метод написан.

Есть ли в Moq специальный способ установки коротких замыканий в частичных пробах?

Foo.cs:

public class Foo
{
    private int _bar;
    public virtual int Bar
    {
        get => _bar;
        set
        {
            MagicNumber+=FooBar;
            _bar = value;
        } 
    }

    private int _fooBar;
    public virtual int FooBar
    {
        get => _fooBar;
        set
        {
            //Complex and heavy logic that makes the magic number -value
            MagicNumber = -value;
            _fooBar = value;
        }
    }

    public int MagicNumber { get; set; }

    public Foo()
    {
        FooBar = 1;
    }
}

FooTests.cs:

[TestFixture]
public class FooTests
{
    //Using ordinary setup.
    [TestCase(1, 2, 2, TestName = "BarSetter_BarSetToOneAndFooBarEqualsTwo_MagicNumberEqualsTwo")]
    public void BarSetterTest(int bar, int fooBar, int expectedMagicNumber)
    {
        var fooPartialMock = new Mock<Foo> {CallBase = true};
        fooPartialMock.Setup(x => x.FooBar).Returns(fooBar);
        fooPartialMock.Object.Bar = bar;
        Assert.AreEqual(expectedMagicNumber, fooPartialMock.Object.MagicNumber);
    }

    //Using callbacks.
    [TestCase(1, 2, 2, TestName = "BarSetter_BarSetToOneAndFooBarEqualsTwo_MagicNumberEqualsTwo2")]
    public void BarSetterTest2(int bar, int fooBar, int expectedMagicNumber)
    {
        var fooPartialMock = new Mock<Foo> { CallBase = true };
        fooPartialMock.SetupSet(x => x.FooBar = It.IsAny<int>()).Callback<int>(x => {});
        fooPartialMock.Object.Bar = bar;
        Assert.AreEqual(expectedMagicNumber, fooPartialMock.Object.MagicNumber);
    }

    //Using SetupProperty.
    [TestCase(1, 2, 2, TestName = "BarSetter_BarSetToOneAndFooBarEqualsTwo_MagicNumberEqualsTwo3")]
    public void BarSetterTest3(int bar, int fooBar, int expectedMagicNumber)
    {
        var fooPartialMock = new Mock<Foo> { CallBase = true };
        fooPartialMock.SetupProperty(x => x.FooBar);
        fooPartialMock.Object.FooBar = fooBar;
        fooPartialMock.Object.Bar = bar;
        Assert.AreEqual(expectedMagicNumber, fooPartialMock.Object.MagicNumber);
    }
}

1 Ответ

0 голосов
/ 18 сентября 2018

Разница в результатах тестов вызвана различным поведением Mock, которое было настроено. Метод Setup В первом тесте просто переопределите метод получения:

Определяет настройку по ложному типу для вызова метода, возвращающего значение.

Так что в этом случае вызов FooBar в конструкторе влияет на MagicNumber. Перегрузка метода SetupSet, который вы использовали во втором тесте, устарела и выглядит так, как будто он не переопределяет установщик, он просто устанавливает ожидание, которое вы сможете проверить позже? включить или добавить обратный вызов:

Указывает настройку для ложного типа для вызова метода установки свойств независимо от его значения.

В этом случае FooBar в конструкторе также влияет на MagicNumber. Однако метод FooBar вызывается дважды: из конструктора и из лямбды, где он вызывается с возвращаемым значением It.IsAny<int>, равным 0. Наконец, SetupProperty из третьего теста задает поведение свойства по умолчанию:

Указывает, что данное свойство должно иметь property behavior, что означает, что установка его значения приведет к его сохранению и последующему возвращению при запросе свойства (это также называется заглушкой)

Таким образом, FooBar в конструкторе не влияет на MagicNumber в третьем тесте, потому что все свойство покрыто заглушкой, и вы никогда не получите FooBar setter. Поэтому третий тест - зеленый. Я полагаю, что конфигурация, которую вы реализовали в третьем тесте, делает то, что вам нужно. Вы можете комбинировать его с первым, чтобы FooBar getter всегда возвращал одно и то же значение:

fooPartialMock.SetupProperty(x => x.FooBar).Setup(x => x.FooBar).Returns(fooBar);

Надеюсь, это поможет.

...