Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/281.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用decorator模式模拟一个抽象类,并包含一个以自身为实例的构造函数_C#_Unit Testing_Oop_Design Patterns_Polymorphism - Fatal编程技术网

C# 如何使用decorator模式模拟一个抽象类,并包含一个以自身为实例的构造函数

C# 如何使用decorator模式模拟一个抽象类,并包含一个以自身为实例的构造函数,c#,unit-testing,oop,design-patterns,polymorphism,C#,Unit Testing,Oop,Design Patterns,Polymorphism,首先,我想澄清的是,这个问题不是重复的,因为当您有一个抽象类时,情况就不同了 我的情况是存在一个基类 public abstract class FooBase { public FooBase(FooBase inner) { /* ... */ } public virtual void DoSomething() { /* ... */ } } 它位于不同的程序集中,我想模拟DoSomething()的行为。问题是如果我尝试创建一个模拟 public class M

首先,我想澄清的是,这个问题不是重复的,因为当您有一个抽象类时,情况就不同了

我的情况是存在一个基类

public abstract class FooBase
{
     public FooBase(FooBase inner) { /* ... */ }

     public virtual void DoSomething() { /* ... */ }
}
它位于不同的程序集中,我想模拟
DoSomething()
的行为。问题是如果我尝试创建一个模拟

public class MockFoo : FooBase
{
    public MockFoo(...) : base(/*I have to put a FooBase in here*/) { /* ... */ }
}

我无法将
new MockFoo()
传递到
base
中,因为它将导致无限递归。我的任何其他想法(比如创建另一个
mockfoooouter
)都无法绕过无限递归问题

我同意恩科西的观点。您需要将任何(如建议的null)值传递给
base
,这将不会导致
FooBase
构造函数中出现异常。

如果要测试装饰器,您不必模拟装饰方法
DoSomething
,而是模拟整个装饰类

首先,您必须修复类设计和装饰器实现:
现在,decorator在构造函数中接受他自己的decorator类型的实例,这是没有意义的。如果是装饰器,则必须接受装饰类型的实例。
这意味着您必须为所有要实现的装饰类型引入一个接口。在本例中,它被命名为
IDecorated

我们的目标是创建一个如下所示的单元测试:

public class UnitTest
{
  public void TestDecorator()
  {
    IDecorated mockOfIDecorated = new DecoratedMock();
    DecoratorBase decoratorBaseTest = new DecoratorBaseTest(mockOfIDecorated);
    // Use decoratorBaseTest instance to test its public members
  }
}
要使模拟成为可能,请引入装饰类型的接口:

public interface IDecorated
{
  void DoSomething();
}
这将更改并修复装饰器类型的构造函数的签名。另外,不要将装饰器的
DoSomething
实现虚拟化,因为这可能会导致不需要的行为(例如,扩展类忘记将调用委托给装饰类型实例)。因此,
虚拟
已被删除。要使子类型的扩展行为可重写,只需添加一个抽象方法:

public abstract class DecoratorBase : IDecorated
{
  private IDecorated decorated;

  // The decorator should always accept an abstract type 
  // or interface of the type to be decorated
  public DecoratorBase(IDecorated decorated)
  {
    this.decorated = decorated;
  }

  public void DoSomething()
  {
    // Delegate calls to the decorated class instance and ...
    this.decorated.DoSomething();

    // ... add functionality by invoking additional members. 
    // Making this member abstract adds customization for subtypes
    DoSomethingToExtendTheDecoratedBehavior();
  }

  public object DoSomethingDecoratorSpecific()
  {
  }

  protected abstract void DoSomethingToExtendTheDecoratedBehavior();
}
由于无法直接测试抽象类,因此需要提供可由测试类实例化的测试实现:

public class DecoratorBaseTest : DecoratorBase
{
  public DecoratorBaseTest(IDecorated mockOfIDecorated) : base(mockOfIDecorated) { /* ... */ }

  #region Overrides of DecoratorBase

  protected override void DoSomethingToExtendTheDecoratedBehavior()
  {
    // Do nothing here because the unit test 
    // tests only public members of DecoratorBase 
  }

  #endregion
}
IDecorated
的模拟类型。对此类型调用
DoSomething()
,不会产生任何效果:

public class DecoratedMock : IDecorated
{
  #region Implementation of IDecorated

  public void DoSomething()
  {
    // Do nothing since this is a mock
  }

  #endregion
}

既然Decorator实现已经修复,您就可以轻松地测试Decorator类。

内部是否可以为null?如果没有一个能够澄清您的具体问题或额外细节以突出显示所做的工作,就很难重现问题,允许更好地理解被询问的内容。您需要展示一个更好的目标类示例。