C#如何正确地测试一个遵循装饰器模式的类?

我对unit testing比较陌生(我实际上正在研究它)

我的目标当然是能够在下面的课程中测试方法。

该类只是检查输入是否已经在缓存中,如果输入不在缓存中,它将返回输入的反转forms(虽然实现不在这里,但假设确实如此,因为目的只是为了测试)。

基本上,目标是确保测试if-else。

这是我的class级:

namespace YouSource.Decorator { using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; ///  /// Caching Decorator ///  public class CachingDecorator : IModifyBehavior { private IModifyBehavior behavior; private static Dictionary cache = new Dictionary(); public string Apply(string value) { ////Key = original value, Value = Reversed var result = string.Empty; //cache.Add("randel", "lednar"); if(cache.ContainsKey(value)) { result = cache[value]; } else { result = this.behavior.Apply(value);// = "reversed"; cache.Add(value, result); } return result; } } } 

这是我测试的当前代码:

 using System; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace YouSource.Decorator.Tests { [TestClass] public class CachingDecoratorTest { private IModifyBehavior behavior; [TestInitialize] public void Setup() { this.behavior = new StubModifyBehavior(new CachingDecorator()); } [TestCleanup] public void Teardown() { this.behavior = null; } [TestMethod] public void Apply_Cached_ReturnsReversedCachedValue() { string input = "randel"; string reversed = "lednar"; Assert.AreEqual(reversed, this.behavior.Apply(input)); } [TestMethod] public void Apply_NotCached_ReturnsReversed() { string input = "not cached"; string reversed = "reversed"; Assert.AreEqual(reversed, this.behavior.Apply(input)); } public class StubModifyBehavior : IModifyBehavior { private IModifyBehavior behavior; public StubModifyBehavior(IModifyBehavior behavior) { this.behavior = behavior; } public string Apply(string value) { //return this.behavior.Apply(value); } } } } 

装饰器动态地将新行为附加到装饰的对象上。 这是装饰者的责任。 那是你应该测试的。

所以,让我们为以下组件编写缓存装饰器:

 public interface IComponent { string DoSomething(string value); } 

创建测试夹具(或TestClass,如果您使用的是MSTest)

 [TestFixture] public class CachingComponentTests { private CachingComponent _cachingComponent; private Mock _componentMock; [SetUp] public void Setup() { _componentMock = new Mock(); // using Moq in this sample _cachingComponent = new CachingComponent(_componentMock.Object); } } 

要编译此代码,您需要创建CachingComponent类,该类接受修饰组件。 这样的东西(这里加速度很小):

 public class CachingComponent : IComponent { private IComponent _component; public CachingComponent(IComponent component) { _component = component; } public string DoSomething(string value) { throw new NotImplementedException(); } } 

现在让我们定义装饰器的预期行为。 它应该将调用传递给组件,如果是第一次使用某个参数调用:

 [Test] public void ShouldCallComponentWhenCalledFirstTime() { _componentMock.Setup(c => c.DoSomething("foo")).Returns("bar"); Assert.That(_cachingComponent.DoSomething("foo"), Is.EqualTo("bar")); _componentMock.Verify(); } 

它失败了因此方法尚未实现。 第一个实现(好吧,最简单的实现将返回null,但我们在这里移动得更快):

  public string DoSomething(string value) { return _component.DoSomething(value); } 

尼斯。 我们的缓存组件按预期工作。 但它并没有缓存任何东西。 为此编写测试。 它应该只调用一次组件。 所有进一步的调用应该返回缓存的值:

 [Test] public void ShouldReturnCachedValueWhenCalledMoreThanOnce() { _componentMock.Setup(c => c.DoSomething("foo")).Returns("bar"); Assert.That(_cachingComponent.DoSomething("foo"), Is.EqualTo("bar")); Assert.That(_cachingComponent.DoSomething("foo"), Is.EqualTo("bar")); _componentMock.Verify(c => c.DoSomething("foo"), Times.Once()); } 

并实施:

 public class CachingComponent : IComponent { private Dictionary _cache = new Dictionary(); private IComponent _component; public CachingComponent(IComponent component) { _component = component; } public string DoSomething(string value) { if (!_cache.ContainsKey(value)) _cache.Add(value, _component.DoSomething(value)); return _cache[value]; } } 

现在你有了经过validation的行为的缓存装饰器。