使用Rhino Mocks删除公共函数内私有函数的依赖性

时间:2010-05-02 07:35:18

标签: mocking rhino

我是嘲笑的新手,并且已经开始使用Rhino Mocks了。我的场景就像这样......在我的类库中我有一个公共函数,在其中我有一个私有函数调用,它从服务中获取输出。我想删除私有函数依赖。

public class Employee
    {        
        public virtual string GetFullName(string firstName, string lastName)
        {
            string middleName = GetMiddleName();
            return string.Format("{0} {2} {1}", firstName, lastName,middleName );
        }

        private virtual string GetMiddleName()
        {
            // Some call to Service

            return "George";
        }
    }

这不是我真实的场景,我只是想知道如何删除GetMiddleName()函数的依赖,我需要在单元测试时返回一些默认值。

注意:我将无法在这里更改私有函数..或者包括接口......保持这样的功能,有没有办法模拟这个。谢谢

2 个答案:

答案 0 :(得分:2)

问题在于这一部分:“私有函数调用,它从服务中获取”。应该注入该服务,以便您可以嘲笑它。如果它创建了服务本身的具体实例,那么我认为Rhino不会帮助你。

TypeMock也许可以帮到你 - 我相信可以让你模仿任何,但代价是更具侵略性。

你不应该删除调用私有方法的依赖关系,你应该删除中的依赖那个私有方法。如果你不能这样做,那么没有类似TypeMock的东西,你的代码就无法测试。

答案 1 :(得分:0)

一种可能的解决方案是使用Extract and Override模式从测试中的类派生一个可测试的类,并覆盖private方法(在您的示例中,该方法应该是private之外的其他方法private方法不能virtual - 也许您的意思是protected?)允许您覆盖该方法。

public class Employee
{        
    public virtual string GetFullName(string firstName, string lastName)
    {
        string middleName = GetMiddleName();
        return string.Format("{0} {2} {1}", firstName, lastName,middleName );
    }

    protected virtual string GetMiddleName()
    {
        // Some call to Service

        return "George";
    }
}

///<summary>
///Testable Employee class
///</summary>
public class TestableEmployee : Employee
{    
    public string MiddleName;

    public virtual string GetFullName(string firstName, string lastName)
    {
        string middleName = GetMiddleName();
        return string.Format("{0} {2} {1}", firstName, lastName,middleName );
    }

    protected override string GetMiddleName()
    {
        // provide own implementation to return 
        // property that we can set in the test method

        return MiddleName;
    }
}

测试方法

[TestMethod]
public GetFullName_ReturnsSetName()
{
    var testEmployee = new TestableEmployee();
    string firstName = "first";
    string middleName = "middle";
    string lastName = "last";

    TestableEmployee.MiddleName = middleName;

    string fullName = GetFullName(firstName, lastName);

    Assert.AreEqual(string.Format("{0} {2} {1}", 
                    firstName, lastName, middleName ), 
                    fullName
                    );
}

如果GetMiddleName()是服务调用的包装器,那么将服务接口作为Employee类的属性可能是一种更可测试的设计。这样,您可以使用“提取和覆盖”模式或使用控制反转(IoC)容器(如UnityCastle Windsor)来模拟服务类型。