1

if-elseステートメントが実行されるかどうかをテストしたいのですが、「if」ブロックはディクショナリ/キャッシュからアイテムを返し、出力を返します。「else」ブロックは、キャッシュ内に入力を追加して出力を返します。

メソッドApplyを使用したIModifyBehaviorのインターフェース

moqを使用して適切に実装できましたが、今はスタブクラス(フレームワークなし)を使用した単体テストを試したいので、偽物を使用せずに実装したいと思います。

私はこのクラスを持っています:

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

これがテストの現在のコードです。コードはテストに合格しましたが、実装が正しいかどうかはわかりません。

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


    }

サー/マームあなたの答えは大いに役立つでしょう。ありがとう++

4

2 に答える 2

2

内部をあまり気にせずに、クラスのコントラクトを実際に実行する単体テストが必要になると思います。たとえば、リフレクションを介して何かを実行したり、新しいメソッドを公開したりして、テストがキャッシュに何をしているのかを問い合わせることができますが、テストはとにかくそれを気にするべきではありません。キャッシュデコレータを見ると、あなたが暗示している契約は次のようなものです:

apply引数付きで呼び出され、値が返されると、その後の引数付きの呼び出しでもx戻り値が返されます。vapplyxv

すでにお持ちのように、メソッドを で 2 回呼び出すテストでは、両方の回数が返さxれることがわかります。vしかし、これがキャッシング デコレータが意図したとおりに動作しているためなのか、基になる反転修飾子がコントラクトに従っているだけなのかはわかりません。

では、これらのルールに従わない基になる修飾子があった場合はどうなるでしょうか?

モックを使用して、IModifyBehavior呼び出された回数を返す の実装をセットアップしたとします。これで、動作が異なります。この実装で apply を同じ引数xで 3 回呼び出すと、3 つの異なる回答が返されます (単体テストで確認できます)。そのモックを CachingDecorator にラップすると、CachingDecorator が最初に見た呼び出しにぶら下がっていて、元のコントラクトに従っていることがわかります。これは、たまたま契約に従っている他のオブジェクトへの呼び出しを単に渡すのではなく、 CachingDecorator の内部が契約に従っていることを「証明」しています。

于 2013-03-13T17:26:42.457 に答える
0

私の最初の質問は、なぜモッキング フレームワークの使用に反対するのですか?

しかし、その下で作業する場合は、独自のモックをロールするだけではなく、独自のモックオブジェクトのロールを参照してください。これにより、外部ライブラリを使用せずに問題が解決します。

于 2013-03-13T17:43:41.980 に答える