在没有实例的情况下使用FakeItEasy A.CallTo和Instance MethodInfo

时间:2014-07-29 10:21:03

标签: c# fakeiteasy

我正在尝试测试一个方法,该方法有一个using语句,用于创建IDisposable类型的新具体实例。

为此,我试图伪造一个在IDisposable类型的构造函数中执行的私有方法。 我可以更改代码,以便更容易测试,但我想知道这种方式是否可行。

到目前为止,我有:

  1. 使用反射来获取指向私有方法的MethodInfo对象
  2. 基于MethodInfo对象
  3. 创建表达式类型
  4. 如果执行该表达式,则告诉FakeItEasy无法执行
  5. 说明我的问题的示例代码

    namespace FakeUsing
    {
        using System;
        using System.Linq.Expressions;
        using System.Runtime.Remoting.Messaging;
    
        using FakeItEasy;
    
        using Microsoft.VisualStudio.TestTools.UnitTesting;
        using System.Reflection;
    
        // Application under test
        class Program
        {
            public bool success = false;
    
            // Entry Point
            static void Main(string[] args)
            {
                Program p = new Program();
                p.Run();
            }
    
            // Method I would like to test
            public void Run()
            {
                using (new Concrete("data"))
                {
                    // Code I actually want to test.
                    success = true;
                }
            }
        }
    
        // Problem class that I cannot change
        public class Concrete : IDisposable
        {
            public Concrete(string data)
            {
                PrivateCall();
            }
    
            private void PrivateCall()
            {
                // Some stuff that uses unmanaged resources
                // I'm not interested in testing
                DoStuff();
            }
    
            public void Dispose()
            {
                // Some stuff that uses unmanaged resources
                // I'm not interested in testing
                DoStuff();
            }
    
            private void DoStuff()
            {
                throw new NotImplementedException();
            }
        }
    
        // Testing code
        [TestClass]
        public class UnitTests
        {
            [TestMethod]
            public void TestRun()
            {
                // Arrange
                Program p = new Program();
                MethodInfo doStuffMethodInfo = 
                   typeof(FakeUsing.Concrete)
                      .GetMethod("DoStuff", BindingFlags.Instance | BindingFlags.NonPublic);
    
                // This is the line I cannot get to work.
                MethodCallExpression doStuffMCE = 
                   Expression.Call(???, doStuffMethodInfo, null);
                A.CallTo(doStuffMCE).DoesNothing();
    
                // Act
                p.Run();
    
                // Assert
                Assert.IsTrue(p.success);
            }
        }
    }
    

    在FakeUsing.UnitTests.TestRun中,我无法绕过创建MethodCallExpression实例,因为我手头没有实例。

    由于

    大卫

1 个答案:

答案 0 :(得分:2)

这是不可能的。 FakeItEasy只能拦截它创建的伪造方法,并且你new生产类进行测试。

即使有可能,我也会反对。模拟private方法通常会导致(最多)过度指定的脆弱测试。一旦实施发生变化,所有测试都会中断。如果(正如您提示的那样),您无法控制具有私有方法的类,这尤其危险。

我认为更好的方法是更改​​生产代码(您可以更改)以使用某种工厂返回IDisposable。然后提供返回无操作对象的工厂实现。使用FakeItEasy时,这应该非常简单。 (或者甚至没有它!行为很简单,如果你还没有,你就不需要一个模拟框架。)