简体   繁体   English

如何仅使用存根类对C#中的if-else语句进行单元测试?

[英]How to unit test an if-else statement in C# using just a stubclass?

I want to test whether the if-else statements are executed, The "if" block returns the item from the dictionary/cache and returns the output, while "else" block adds the input inside the cache and returns an output 我想测试是否执行了if-else语句,“ if”块从字典/缓存中返回项目并返回输出,而“ else”块在缓存中添加输入并返回输出

An interface of IModifyBehavior with a method Apply IModifyBehavior的接口与方法Apply

I was able to implement it properly using moq, but now what I want to try is unit test just using a stubclass (no framework), I also want to implement it without using fakes. 我能够使用moq正确实现它,但是现在我想尝试的是仅使用stubclass(无框架)进行单元测试,我也想实现它而不使用伪造品。

I have this classes: 我有这个课程:

namespace Decorator
{
    using System;

    /// <summary>
    /// Reverse Behavior
    /// </summary>
    public class ReverseBehavior : IModifyBehavior
    {
        /// <summary>
        /// Applies the specified value.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns>result</returns>
        public string Apply(string value)
        {
            var result = string.Empty;
            if (value != null)
            {
                char[] letters = value.ToCharArray();
                Array.Reverse(letters);
                result = new string(letters); 
            }

            return result; 
        }
    }
}




using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;

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

        /// <summary>
        /// The behavior
        /// </summary>
        private IModifyBehavior behavior;


        public CachingDecorator(IModifyBehavior behavior)
        {
            if (behavior == null)
            {
                throw new ArgumentNullException("behavior");
            }

            this.behavior = behavior;
        }



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

        /// <summary>
        /// Applies the specified value.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns>
        /// value
        /// </returns>
        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";
                ////Note:Add(key,value)
                cache.Add(value, result); 
            }
            return result;
        }
    }
}

Here's my current code for the test, the codes were able to passed the test, but I'm not sure if my implementation was correct: 这是我当前的测试代码,这些代码能够通过测试,但是我不确定我的实现是否正确:

[TestClass]
    public class CachingDecoratorTest
    {
        private IModifyBehavior behavior;

        [TestInitialize]
        public void Setup()
        {
            this.behavior = new CachingDecorator(new ReverseBehavior());
        }

        [TestCleanup]
        public void Teardown()
        {
            this.behavior = null;
        }

        [TestMethod]
        public void Apply_Cached_ReturnsReversedCachedValue()
        {
            string actual = "randel";           
            ////store it inside the cache
            string cached = this.behavior.Apply(actual);

            ////call the function again, to test the else block statement
            ////Implement DRY principle next time
            string expected = this.behavior.Apply(actual);
            Assert.IsTrue(cached.Equals(expected));

        }

        [TestMethod]
        public void Apply_NotCached_ReturnsReversed()
        {
            string actual = "randel";
            string expected = "lednar";
            Assert.AreEqual(expected, this.behavior.Apply(actual));
        }


    }

Sir/Ma'am your answers would be of great help. 先生/女士,您的回答会很有帮助。 Thank you++ 谢谢++

I would think that you would want a unit test that really exercises the contract of the class without worrying about the internals too much. 我认为您需要一个单元测试,该单元测试实际上可以执行课程的合同 ,而不必过多担心内部问题。 You could, for example, do something via reflection, or expose some new method, that allows your test to ask the cache what it's doing, but your test shouldn't care about that anyway. 例如,您可以通过反射来做某事,或者公开一些新方法,以使您的测试可以询问缓存正在做什么,但是您的测试无论如何都不应该在意。 If I look at the caching decorator, the contract you have implied is something like : 如果我看一下缓存装饰器,那么您所隐含的合同就像:

Once apply has been called with argument x and returning value v , any subsequent call to apply with argument x will also return v . 一旦apply已调用参数x和返回值v ,任何后续调用apply与参数x也将返回v

So as you already have, a test that calls the method twice with x can show that we get v back both times. 因此,正如您已经拥有的,使用x两次调用该方法的测试可以表明我们两次都获得了v But we can't tell that this is because the caching decorator is doing what we want, or if it's because the underlying reversal modifier is just following the contract. 但是我们不能说这是因为缓存装饰器正在执行我们想要的操作,或者是因为基础反转修饰符仅在合同之后。

So what if we had an underlying modifier that didn't play by those rules? 那么,如果我们有一个不符合这些规则的基础修饰符怎么办?

Suppose, using a mock, you set up an implementation of IModifyBehavior that returned the number of times it had been invoked? 假设您使用模拟程序设置了IModifyBehavior的实现,该实现返回了被调用的次数? Now we've got a different behavior - if I call apply on this implementation 3 times with the same argument x , I will get back 3 different answers (which can be verified with a unit test). 现在我们有了不同的行为-如果我使用相同的参数x对该应用调用3次,则我将获得3个不同的答案(可以通过单元测试进行验证)。 If I then wrap that mock in your CachingDecorator, I can see that the CachingDecorator is hanging onto the first invocation that it saw, and abiding by the original contract. 然后,如果将该模拟包装在您的CachingDecorator中,则可以看到CachingDecorator挂在它看到的第一个调用上,并且遵守原始合同。 This 'proves' to me that the internals of CachingDecorator are following the contract instead of just passing along the invocation to some other object that happens to also follow the contract. 这向我证明了CachingDecorator的内部结构遵循合同,而不仅仅是将调用传递给恰好也遵循合同的其他对象。

My first question is why are you opposed to using a mocking framework? 我的第一个问题是您为什么反对使用模拟框架?

But working under that, why not just roll your own mock see Rolling your own mock objects , this solves your problem without using external libs. 但是在这种情况下,为什么不只是滚动自己的模拟对象 ,参见滚动自己的模拟对象 ,这可以解决您的问题而无需使用外部库。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM