Как выполнить модульное тестирование метода расширения, конвертирующего Action в Func? - PullRequest
0 голосов
/ 09 мая 2019

Я пишу небольшую библиотеку Functional C #, в которой я определил тип Unit `, а также несколько методов расширения для преобразования:

  • Action
  • Action<T1>
  • Func<T1, T2>
  • Etc.

Кому:

  • Func<Unit>
  • Func<T1, Unit>
  • Func<T1,T2, Unit>
  • 1029 * Etc. *
public static partial class ActionExtensions
{
    public static Func<Unit> ToFunc(this Action action) =>
    () =>
    {
        action();
        return Unit.Default;
    };

    public static Func<T, Unit> ToFunc<T>(this Action<T> action) =>
        t =>
        {
            action(t);
            return Unit.Default;
        };

    public static Func<T1, T2, Unit> ToFunc<T1, T2>(this Action<T1, T2> action) =>
        (t1, t2) =>
        {
            action(t1, t2);
            return Unit.Default;
        };

     // other methods...

Unit определяется следующим образом:

public readonly struct Unit : IEquatable<Unit>
{
    public static readonly Unit Default = new Unit();

    public override int GetHashCode() => 
        0;

    public override bool Equals(object obj) =>
        obj is Unit;

    public bool Equals(Unit other) =>
        true;

    public static bool operator ==(Unit left, Unit right) =>
        true;

    public static bool operator !=(Unit left, Unit right) =>
        false;
}

Мне интересно, как выполнить модульное тестирование этих методов расширения.

Должен ли я выполнить какое-либо отражение для анализа типа возвращаемого значения, а также параметров Func, должен ли я проверять, что при вызове Func это вызывает базовый метод Action?

Есть мысли?

Ответы [ 2 ]

3 голосов
/ 09 мая 2019

Самое простое было бы передать действие, которое устанавливает логическое значение равным true, когда оно вызывается, и затем проверить результат вашего метода расширения.Это доказывает ожидаемое поведение, которое

  • вызывается действие
  • функция возвращается с единицей по умолчанию

Например,

[Test] public void ToFuncForGivenActionInvokesAction()
{
    // arrange
    bool invoked = false;
    Action action = () => invoked = true;

    // act
    var func = action.ToFunc();

    // assert
    func().Should().Be(Unit.Default);
    invoked.Should().BeTrue();
}

В приведенном выше

  • Я использую Свободные утверждения для подтверждения, но вы можете использовать все, что хотите, конечно
  • Не беспокойтесьпроверка func на ноль.Тестирование результата func() охватывает этот случай.Меньше шума.
  • Повторите для ваших действий, которые принимают параметры.

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

2 голосов
/ 09 мая 2019

Используя фальшивый фреймворк, такой как NSubstitute , вы можете легко утверждать, что данный метод / действие был вызван, а также что значения переданных аргументов соответствуют ожидаемым.

В приведенном ниже примере я использую тестовый фреймворк xUnit .

Assert testDummy.Received().Run("foobar", 123); провалит тест, если

  1. the Run метод не был выполнен
  2. метод Run получил бы другие значения аргумента, чем foobar и 123.

public interface ITestDummy
{
    void Run(String arg1, Int32 arg2);
}

public class UnitTest
{
    [Fact]
    public void Test1()
    {   
        var testDummy = Substitute.For<ITestDummy>();

        Action<String, Int32> action = testDummy.Run;  
        Func<String, Int32, Unit> func = action.ToFunc();

        var result = func("foobar", 123);

        testDummy.Received().Run("foobar", 123);
        Assert.Equal(result, Unit.Default);
    }
}
...