C#中如何正确单元测试,遵循一个装饰图案的一类? [英] C# How to properly unit test a class that follows a decorator pattern?

查看:97
本文介绍了C#中如何正确单元测试,遵循一个装饰图案的一类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是相当新的单元测试(实际上,我研究它,因为我们说话)

我的目标是当然的,以便能够内部测试方法以下的类。

类简单地检查输入是否已经在高速缓存中,如果输入没有在高速缓存中,它会返回输入的反转形式(虽然实现并不在这里,但假设是这样,由于目的是只是为了测试)。

基本上目标是确保如果其他被测试

下面是我的类:

 命名空间YouSource.Decorator
{
    使用系统;
    使用System.Collections.Generic;
    使用System.Linq的;
    使用System.Text;
    使用System.Threading.Tasks;

    ///<总结>
    ///缓存装饰
    ///< /总结>
    公共类CachingDecorator:IModifyBehavior
    {
       私人IModifyBehavior行为;

       私有静态字典<字符串,字符串>缓存=
           新的字典<字符串,字符串>();

        公共字符串应用(字符串值)
        {
            ////重点=原始值,值=反转
            VAR的结果=的String.Empty;

            //cache.Add("randel,lednar);
            如果(cache.ContainsKey(值))
            {

                结果=缓存[值];

            }
            其他
            {

                结果= this.behavior.Apply(值); // =逆转;
                cache.Add(值,结果);
            }
            返回结果;
        }
    }
}
 

下面是我的测试当前的code:

 使用系统;
使用Microsoft.VisualStudio.TestTools.UnitTesting;

命名空间YouSource.Decorator.Tests
{
    [识别TestClass]
    公共类CachingDecoratorTest
    {
        私人IModifyBehavior行为;

        [TestInitialize]
        公共无效设置()
        {
            this.behavior =新StubModifyBehavior(新CachingDecorator());
        }

        [TestCleanup]
        公共无效拆解()
        {
            this.behavior = NULL;
        }

        [测试方法]
        公共无效Apply_Cached_ReturnsReversedCachedValue()
        {
            字符串输入=兰德尔;
            字符串逆转=lednar;
            Assert.AreEqual(逆转,this.behavior.Apply(输入));
        }

        [测试方法]
        公共无效Apply_NotCached_ReturnsReversed()
        {
            字符串输入=不缓存;
            字符串逆转=逆转;
            Assert.AreEqual(逆转,this.behavior.Apply(输入));
        }

        公共类StubModifyBehavior:IModifyBehavior
        {
            私人IModifyBehavior行为;

            公共StubModifyBehavior(IModifyBehavior行为)
            {
                this.behavior =行为;
            }

            公共字符串应用(字符串值)
            {

                //返回this.behavior.Apply(值);
            }
        }
    }
}
 

解决方案

装饰动态地重视新的行为对象是装饰。这是装饰的责任。这是你应该测试。

因此​​,让写缓存装饰为以下组件:

 公共接口IComponent的
{
    字符串DoSomething的(字符串值);
}
 

创建测试治具(或TestClass的,如果你正在使用MSTest的)

  [的TestFixture]
公共类CachingComponentTests
{
    私人CachingComponent _cachingComponent;
    私人模拟< IComponent的> _componentMock;

    [建立]
    公共无效设置()
    {
        _componentMock =新的模拟< IComponent的>(); //使用起订量在此示例
        _cachingComponent =新CachingComponent(_componentMock.Object);
    }
}
 

有关此code编译你需要创建CachingComponent类,它接受的装饰部件。类似的东西(小速度在这里):

 公共类CachingComponent:IComponent的
{
    私人IComponent的_component;

    公共CachingComponent(IComponent的组件)
    {
        _component =组件;
    }

    公共字符串DoSomething的(字符串值)
    {
        抛出新的NotImplementedException();
    }
}
 

现在让我们定义装饰的预期行为。它应该通过调用组件,如果是这样的一些参数的第一个电话:

  [测试]
公共无效ShouldCallComponentWhenCalledFirstTime()
{
    _componentMock.Setup(C => c.DoSomething(富))将返回(巴)。

    Assert.That(_cachingComponent.DoSomething(富),Is.EqualTo(酒吧));
    _componentMock.Verify();
}
 

和它没有这样的方法还没有实现。首先实现(当然,简单的实现将返回null,但我们正在这里快一点):

 公共字符串DoSomething的(字符串值)
    {
        返回_component.DoSomething(值);
    }
 

尼斯。我们的缓存组件按预期工作。但它不缓存任何东西。写作考试为。它应该调用组件只有一次。所有后续调用应该返回的缓存值:

  [测试]
公共无效ShouldReturnCachedValueWhenCalledMoreThanOnce()
{
    _componentMock.Setup(C => c.DoSomething(富))将返回(巴)。

    Assert.That(_cachingComponent.DoSomething(富),Is.EqualTo(酒吧));
    Assert.That(_cachingComponent.DoSomething(富),Is.EqualTo(酒吧));
    _componentMock.Verify(C => c.DoSomething(富),Times.Once());
}
 

和实施

 公共类CachingComponent:IComponent的
{
    私人字典<字符串,字符串> _cache =新字典<字符串,字符串>();
    私人IComponent的_component;

    公共CachingComponent(IComponent的组件)
    {
        _component =组件;
    }

    公共字符串DoSomething的(字符串值)
    {
        如果(!_cache.ContainsKey(值))
            _cache.Add(值,_component.DoSomething(值));

        返回_cache [值];
    }
}
 

现在你有缓存装饰与验证的行为。

I'm fairly new to unit testing(I'm actually studying it as we speak)

My goal is of course to be able to test the method inside the class below.

The class simply checks if the input is already in the cache, if the input is not in the cache, it will return the reversed form of the input(though the implementation is not here, but assuming it does, since the purpose is just to test).

Basically the goal is to make sure the if-else is tested.

Here is my class:

namespace YouSource.Decorator
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;

    /// <summary>
    /// Caching Decorator
    /// </summary>
    public class CachingDecorator : IModifyBehavior
    {
       private IModifyBehavior behavior;

       private static Dictionary<string, string> cache = 
           new Dictionary<string, string>();

        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;
        }
    }
}

Here is the current code of my test:

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);
            }
        }
    }
}

解决方案

Decorator dynamically attaches new behavior to object which is decorated. That is responsibility of decorator. That is what you should test.

So, lets write caching decorator for following component:

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

Creating test fixture (or TestClass, if you are using MSTest)

[TestFixture]
public class CachingComponentTests
{
    private CachingComponent _cachingComponent;
    private Mock<IComponent> _componentMock;

    [SetUp]
    public void Setup()
    {
        _componentMock = new Mock<IComponent>(); // using Moq in this sample
        _cachingComponent = new CachingComponent(_componentMock.Object);
    }
}

For this code to compile you need to create CachingComponent class, which accepts decorated component. Something like that (little speed up here):

public class CachingComponent : IComponent
{
    private IComponent _component;

    public CachingComponent(IComponent component)
    {            
        _component = component;
    }

    public string DoSomething(string value)
    {
        throw new NotImplementedException();
    }
}

Now let's define expected behavior of decorator. It should pass call to component, if that is first call with some parameter:

[Test]
public void ShouldCallComponentWhenCalledFirstTime()
{
    _componentMock.Setup(c => c.DoSomething("foo")).Returns("bar");

    Assert.That(_cachingComponent.DoSomething("foo"), Is.EqualTo("bar"));
    _componentMock.Verify();
}

And it fails thus method is not implemented yet. First implementation (well, simplest implementation will be returning null, but we are moving little faster here):

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

Nice. Our caching component works as expected. But it is not caching anything. Writing test for that. It should call component only once. All further calls should return cached 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());
}

And implementation:

public class CachingComponent : IComponent
{
    private Dictionary<string, string> _cache = new Dictionary<string, string>();
    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];
    }
}

Now you have caching decorator with verified behavior.

这篇关于C#中如何正确单元测试,遵循一个装饰图案的一类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆