【问题标题】:NUnit - Static Vs. Public methodsNUnit - 静态与。公共方法
【发布时间】:2013-07-22 20:47:13
【问题描述】:

我的项目在规模和功能上都在增长,所以我决定使用 NUnit 测试一些功能,但是我面临的问题是大多数方法都是静态的,所以我首先想到的是创建公共方法我从单元测试类调用它们但是那些公共方法开始很多,所以我想知道是否应该在主类中创建新的公共方法,而不是创建一个接口,或者静态的应该是公共的并且是使用类中间实例化。

这是我的程序结构的示例,

namespace Mynamespace
{
    public class Foo
    {
         InsertUser();
         SortUser();
    }

    static void InsertUser()
    {

    }

    static void SortUser()
    {

    }

    //Here start the public methods to be called from the unit test class

    public DoSort() 
    {
        InsertUser();
        SortUser();
    }
}

将程序的主要逻辑与测试类分开的最佳方法是什么?

谢谢,

【问题讨论】:

    标签: c# .net unit-testing nunit


    【解决方案1】:

    与其保留静态方法并添加非静态方法,不如将所有方法从静态方法转换为实例方法并提取 Foo 类的客户端所依赖的抽象:

    public interface IFoo
    {
         void InsertUser();
         void SortUser();
    }
    
    public class Foo : IFoo
    {
         void InsertUser() { ... }
         void SortUser() { ... }
    }
    

    静态成员将耦合引入您的应用程序。模拟静态成员真的很头疼。您应该program to abstraction, instead of programing to implementation 以使您的代码可测试并loosely coupled。当你的代码依赖接口而不是静态类时,你可以轻松mock这个依赖:

    Mock<IFoo> fooMock = new Mock<IFoo>();
    fooMock.Setup(f => f.InsertUser()).Throws<InvalidOperationException>();
    
    var sut = new ClassUnderTest(fooMock.Object);
    fooMock.VerifyAll();
    

    如果你真的需要在全局范围内访问这些方法(这不是一个好主意 - 这是一种程序化的编程风格),那么将你的类实现为Singleton

    public class Foo : IFoo
    {
         public static Foo Instance = new Foo(); // simple singleton implementation
         private Foo() { }
    
         void InsertUser() { ... }
         void SortUser() { ... }
    }
    

    您将能够在应用程序的任何位置获取类实例

    IFoo foo = Foo.Instance;
    foo.SortUser();
    

    【讨论】:

    • 我正在将所有方法从静态移动到实例。感谢您提供有关关注抽象而不是实现的建议。
    【解决方案2】:

    在我看来,你应该让你的真实类和你的单元类都实现一个通用接口,像这样:

    interface IFoo
    {
        void InsertUser();
        void SortUser();
    }
    

    对于你的实际实现,使用这个:

    public class RealFoo : IFoo
    {
        public void InsertUser()
        {
            throw new NotImplementedException();
        }
    
        public void SortUser()
        {
            throw new NotImplementedException();
        }
    }
    

    对于你的测试类,使用这个:

    public class FakeFoo : IFoo
    {
        public void InsertUser()
        {
            throw new NotImplementedException();
        }
    
        public void SortUser()
        {
            throw new NotImplementedException();
        }
    }
    

    注意:您的FakeFoo 类不需要与您的RealFoo 类存在于同一位置,而是每个项目都应该引用您的IFoo 接口定义(一个用于实际实现,另一个用于实际实现)在您的测试项目中)。

    如果你的IFoo 接口变得太大(阅读:方法太多),那么你可以使用Repository Pattern,它会根据功能将你的方法分割成更多的接口。

    【讨论】:

    • +1 因为关于命名类和异常处理的提示,非常感谢。谢谢卡尔。
    猜你喜欢
    • 2011-04-19
    • 1970-01-01
    • 1970-01-01
    • 2012-02-11
    • 1970-01-01
    • 2011-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多