Mocking Static Methods

前端 未结 6 2195
佛祖请我去吃肉
佛祖请我去吃肉 2020-11-27 15:11

Recently, I\'ve begun to use Moq to unit test. I use Moq to mock out classes that I don\'t need to test.

How do you typically deal with static methods?



        
6条回答
  •  没有蜡笔的小新
    2020-11-27 15:25

    I've been playing around with a concept of refactoring the static methods to invoke a delegate which you can externally set for testing purposes.

    This would not use any testing framework and would be a completely bespoke solution however the refactor will not influence the signature of your caller and so it would be a relatively safe.

    For this to work, you would need to have access to the static method, so it wouldn't work for any external libraries such as System.DateTime.

    Heres an example I've been playing with where I've created a couple of static methods, one with a return type that takes in two parameters and one generic which has no return type.

    The main static class:

    public static class LegacyStaticClass
    {
        // A static constructor sets up all the delegates so production keeps working as usual
        static LegacyStaticClass()
        {
            ResetDelegates();
        }
    
        public static void ResetDelegates()
        {
            // All the logic that used to be in the body of the static method goes into the delegates instead.
            ThrowMeDelegate = input => throw input;
            SumDelegate = (a, b) => a + b;
        }
    
        public static Action ThrowMeDelegate;
        public static Func SumDelegate;
    
        public static void ThrowMe() where TException : Exception, new()
            => ThrowMeDelegate(new TException());
    
        public static int Sum(int a, int b)
            => SumDelegate(a, b);
    }
    

    The Unit Tests (xUnit and Shouldly)

    public class Class1Tests : IDisposable
    {
        [Fact]
        public void ThrowMe_NoMocking_Throws()
        {
            Should.Throw(() => LegacyStaticClass.ThrowMe());
        }
    
        [Fact]
        public void ThrowMe_EmptyMocking_DoesNotThrow()
        {
            LegacyStaticClass.ThrowMeDelegate = input => { };
    
            LegacyStaticClass.ThrowMe();
    
            true.ShouldBeTrue();
        }
    
        [Fact]
        public void Sum_NoMocking_AddsValues()
        {
            LegacyStaticClass.Sum(5, 6).ShouldBe(11);
        }
    
        [Fact]
        public void Sum_MockingReturnValue_ReturnsMockedValue()
        {
            LegacyStaticClass.SumDelegate = (a, b) => 6;
            LegacyStaticClass.Sum(5, 6).ShouldBe(6);
        }
    
        public void Dispose()
        {
            LegacyStaticClass.ResetDelegates();
        }
    }
    

提交回复
热议问题