c# - 是否应该在接口(interface)中声明所有公共(public)方法?

标签 c# unit-testing interface

给定如下界面:

public interface IFoo
{
    string Bar();
}

还有一个实现它的类:

public class Foo : IFoo
{
    public string Bar()
    {
        returns "Bar";
    }

    public string SomeOtherMethod()
    {
        returns "Something else";
    }
}

这段代码有问题吗?我们是否应该将所有方法都添加到接口(interface)中?

一个例子:想象一个私有(private)方法变得复杂到需要单元测试。您能否将其公开(以便可以从测试项目中调用它)但不将其添加到接口(interface)中(因为没有客户端需要调用它)?

最佳答案

如果一个类做的事情足够简单,我们可以同时测试它的公共(public)方法和私有(private)方法,那么我们可以只测试公共(public)方法。

如果私有(private)方法变得如此复杂以至于在公共(public)方法和私有(private)方法之间我们需要太多的测试组合,那么是时候将私有(private)方法分离到它自己的类中了。公开私有(private)方法会破坏类的封装。即使我们不将方法添加到 interface,将类方法设为 public 仍然会将方法添加到类本身的公共(public)接口(interface)

所以如果我们有这个:

public class ClassWithComplexPrivateMethod
{

    public void DoSomething(int value)
    {
        PrivateMethodThatNeedsItsOwnTests(value);
    }

    private string PrivateMethodThatNeedsItsOwnTests(int value)
    {
        // This method has gotten really complicated!
        return value.ToString();
    }
}

我们可能会重构为这样的东西:

public interface IRepresentsWhatThePrivateMethodDid
{
    string MethodThatNeedsItsOwnTests(int value);
} 

public class RefactoredClass
{
    private readonly IRepresentsWhatThePrivateMethodDid _dependency;

    public RefactoredClass(IRepresentsWhatThePrivateMethodDid dependency)
    {
        _dependency = dependency;
    }

    public string DoSomething(int value)
    {
        return _dependency.MethodThatNeedsItsOwnTests(value);
    }
}

现在一个新类实现了 IRepresentsWhatThePrivateMethodDid

现在,当我们测试重构的类时,我们模拟 IRepresentsWhatThePrivateMethodDid,并且我们为任何实现 IRepresentsWhatThePrivateMethodDid 的类编写单独的单元测试。

将私有(private)方法公开为公共(public)方法会破坏封装,但将其作为自己的独立类公开则不会,这似乎是自相矛盾的。有两个区别:

  • 重构后的类不依赖于包含以前私有(private)方法的新类。这取决于新界面。
  • 重构后的类和接口(interface)之间的交互仍然隐藏在它的方法中。调用其公共(public)方法的其他类并不“知道”它如何使用其依赖项。 (事实上​​,其他类可能会依赖于抽象而不是直接依赖于重构的类。)

当我们本可以通过公共(public)方法测试该类(包括其私有(private)方法)时,也很容易被它冲昏头脑并过早引入单独的依赖项。我已经这样做过很多次了,它会导致很多很多不必要的接口(interface)和额外的类。没有完美,只有我们尽最大努力来平衡它。


还有一个想法:我们倾向于使用接口(interface)来表示依赖关系,但我们不必这样做。如果我们提取的只是一个私有(private)方法,那么也许我们可以用委托(delegate)或 Func 来表示它,如下所示:

public class RefactoredClass
{
    private readonly Func<int, string> _dependency;

    public RefactoredClass(Func<int, string> dependency)
    {
        _dependency = dependency;
    }

    public string DoSomething(int value)
    {
        return _dependency(value);
    }
}

或者我们可以使用委托(delegate),我比 Func 更喜欢它,因为它指示函数的作用。

关于c# - 是否应该在接口(interface)中声明所有公共(public)方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55942632/

相关文章:

C# Int 和数学不返回完整值

c# - 如何在 ASP.Net C# 中实现 FCM?

java - "Facade design pattern"和 Java 接口(interface)在概念上是否相同?

c++ - 寻求重新设计界面的建议

c - 使用 GoogleMock 指定输出字符串参数

c++ - `undefined reference` 尝试连接 C 以调用 C++

c# - 如何中止在另一个函数内启动的线程?

c# - 在 C# 中根据引用的 XSD 验证 XML

python - 访问了模拟实例上的断言属性

c# - 第一个没有断言/预期异常的 TDD 测试。这值得么?