From d2b37932bba93c53f3b34e1ae67b5918014bf41d Mon Sep 17 00:00:00 2001
From: bicijinlian <bicijinlian@163.com>
Date: Sun, 29 Jul 2018 23:23:55 +0800
Subject: [PATCH] MoqDemo update

---
 MoqStudy.Test/MoqDemoTest.cs | 375 +++++++++++++++++++++++------------
 1 file changed, 247 insertions(+), 128 deletions(-)

diff --git a/MoqStudy.Test/MoqDemoTest.cs b/MoqStudy.Test/MoqDemoTest.cs
index f425bbb..34517f2 100644
--- a/MoqStudy.Test/MoqDemoTest.cs
+++ b/MoqStudy.Test/MoqDemoTest.cs
@@ -21,9 +21,12 @@ namespace MoqStudy.Test
     /// </summary>
     public class MoqDemoTest:IDisposable
     {
+        //说明:因为是个人学习用,所有注释比较多
+
         #region xUnit 初始准备
         Mock<IFoo> mock = new Mock<IFoo>();
         IFoo ifoo;
+        delegate void SubmitCallback(ref Bar bar);
         public MoqDemoTest()
         {
             ifoo = mock.Object;
@@ -196,7 +199,47 @@ namespace MoqStudy.Test
             Assert.Equal(4, ifoo.GetCount());
         }
 
+        /// <summary>
+        /// 重复设置
+        /// 后面的设置会覆盖前面的设置
+        /// </summary>
+        [Fact]
+        public void Method_RepeatSet_Test()
+        {
+            mock.//首次设置
+                Setup(f => f.DoSomething("ping"))
+                .Returns(true);
+            Assert.True(ifoo.DoSomething("ping"));
+
+            mock.//重复设置相同参数
+                Setup(f => f.DoSomething("ping"))
+                .Returns(false);
+
+            //后面的设置,覆盖前面的设置
+            Assert.False(ifoo.DoSomething("ping"));
+        }
+
+        /// <summary>
+        /// 多次设置同一参数不同值的返回值
+        /// 保持多次设置
+        /// </summary>
+        [Fact]
+        public void Method_MultiSet_Test()
+        {
+            mock.//设置参数为"ping"
+                Setup(f => f.DoSomething("ping"))
+                .Returns(true);
+
+            mock.//设置参数为"xyz"
+                Setup(f => f.DoSomething("xyz"))
+                .Returns(true);
+
+            Assert.True(ifoo.DoSomething("ping"));
+            Assert.True(ifoo.DoSomething("xyz"));
 
+            //其它均为false
+            Assert.False(ifoo.DoSomething("abc1232"));
+        }
         #endregion
 
         #region 匹配参数
@@ -312,97 +355,180 @@ namespace MoqStudy.Test
         /// 设置属性
         /// </summary>
         [Fact]
-        public void Properties_Setup_Test()
+        public void Property_Setup_Test()
         {
-            var mock = new Mock<IFoo>();
-            var ifoo = mock.Object;
+            mock //设置属性值
+                .Setup(f => f.Name)
+                .Returns("wanggaofeng");
 
-            //设置属性值
-            mock.Setup(f => f.Name).Returns("wanggaofeng");
             Assert.Equal("wanggaofeng", ifoo.Name);
+        }
+
+        /// <summary>
+        /// 自动模拟多层属性
+        /// (递归模拟属性)
+        /// </summary>
+        [Fact]
+        public void Property_Setup_Recursive_Test()
+        {
+            mock //自动模拟多层(即递归Mocks)
+                .Setup(f => f.Bar.Baz.Name)
+                .Returns("Bar.Baz.Name");
 
-            // auto-mocking hierarchies (a.k.a. recursive mocks)
-            // 自动模拟多层(即递归Mocks)
-            mock.Setup(f => f.Bar.Baz.Name).Returns("Bar.Baz.Name");
             Assert.Equal("Bar.Baz.Name", ifoo.Bar.Baz.Name);
         }
 
         /// <summary>
-        /// 设置属性:todo SetupSet用法
+        /// 验证属性设置
         /// </summary>
         [Fact]
-        public void Properties_SetupSet_Test()
+        public void Property_VerifySet_Test()
         {
-            var mock = new Mock<IFoo>();
-            var ifoo = mock.Object;
+            MockException verifyException = null;
 
-            //expects an invocation to set the value to "foo"
-            //期望将调用值设置为“foo”
-            var cc= mock.SetupSet(foo => foo.Name = "foo");
-            Assert.Equal("foo", ifoo.Name);
+            //不执行,为属性赋指定的值,则验证出现异常
+            try
+            {
+                //检查代码 foo.Name = "foo" 已经执行过
+                mock.VerifySet(foo => foo.Name = "foo");
+
+                verifyException = null;
+            }
+            catch (MockException ex)
+            {
+                verifyException = ex;
+            }
+
+            //验证发生异常
+            Assert.NotNull(verifyException);
+
+            //为属性赋指定的值,验证通过
+            try
+            {
+                mock //设置属性(loose模式下,可以不设置)
+                    .Setup(f => f.Name)
+                    .Returns("bbb");
+
+                //执行赋值语句
+                ifoo.Name = "foo";
+
+                //检查代码 foo.Name = "foo" 已经执行过
+                mock.VerifySet(foo => foo.Name = "foo");
+
+                verifyException = null;
+            }
+            catch (MockException ex)
+            {
+                verifyException = ex;
+            }
+
+            Assert.Equal("bbb", ifoo.Name);
+            Assert.Null(verifyException);
+        }
+
+        /// <summary>
+        /// 期望(等同于检查),属性已经被设置为指定的值
+        /// 用法暂不明确:可以用VerifySet替代本功能
+        /// </summary>
+        [Fact]
+        public void Property_SetupSet_Test()
+        {
+            mock //todo:用法不明确,待查
+                 //可以使用 VerifySet 替代
+                .SetupSet(foo => foo.Name = "foo");
+
+
+            Assert.Equal(1,2);
         }
 
         /// <summary>
         /// 验证设置属性
+        /// 用法暂不明确:可以用VerifySet替代本功能
         /// </summary>
         [Fact]
-        public void Properties_SetupGet_Test()
+        public void Property_SetupGet_Test()
         {
-            var mock = new Mock<IFoo>();
-            var ifoo = mock.Object;
+            mock //todo:用法不明确,待查
+                .SetupGet(foo => foo.Name);
 
-            // verify the setter directly
-            mock.SetupGet(foo => foo.Name);
-            ifoo.Name = "foo";
-            Assert.Equal("foo", ifoo.Name);
+            Assert.True(1==2);
         }
 
         /// <summary>
-        /// Setup a property so that it will automatically start tracking its value (also known as Stub)
-        /// 设置属性以使其自动开始跟踪其值(也称为存根)
+        /// 设置后,改变属性值,再次调用时,属性值不变
         /// </summary>
         [Fact]
-        public void Properties_SetupProperty_Test()
+        public void Property_Setup_Change_Test()
         {
-            var mock = new Mock<IFoo>();
+            mock.Setup(f => f.Name)
+                .Returns("ping");
 
-            // start "tracking" sets/gets to this property
-            // 开始“跟踪”设置/获取此属性
-            mock.SetupProperty(f => f.Name);
+            Assert.Equal("ping", ifoo.Name);
 
-            // alternatively, provide a default value for the stubbed property
-            // 或者,为插入属性提供默认值。
-            mock.SetupProperty(f => f.Name, "foo");
+            //为属性赋新值
+            ifoo.Name = "ack";
 
+            //再次调用,属性值保持"ping"不变
+            Assert.False(ifoo.Name == "ack");
+            Assert.True(ifoo.Name == "ping");
+        }
 
-            // Now you can do:
-            // 现在你可以这么做:
+        /// <summary>
+        /// 重复设置属性
+        /// 后面设置的属性值,覆盖前面的设置
+        /// </summary>
+        [Fact]
+        public void Property_Repeat_Setup_Test()
+        {
+            mock //设置属性值为 ping
+                .Setup(f => f.Name)
+                .Returns("ping");
 
-            IFoo foo = mock.Object;
-            // Initial value was stored
-            // 初始值被存储
-            Assert.Equal("foo", foo.Name);
+            Assert.Equal("ping", ifoo.Name);
 
-            // New value set which changes the initial value
-            // 新的设定值改变初始值
-            foo.Name = "bar";
-            Assert.Equal("bar", foo.Name);
+            mock //再次设置属性值为 ack
+                .Setup(f => f.Name)
+                .Returns("ack");
+
+            Assert.Equal("ack", ifoo.Name);
         }
 
         /// <summary>
-        /// Stub all properties on a mock (not available on Silverlight)
-        /// 存根所有模拟属性
+        /// 存根设置的属性值
+        /// 设置后自动开始跟踪属性值,为属性赋值后,调用属性值踉着改变
         /// </summary>
         [Fact]
-        public void Properties_SetupAllProperties_Test()
+        public void Property_SetupProperty_Test()
         {
-            var mock = new Mock<IFoo>();
-            var ifoo = mock.Object;
-            mock.SetupAllProperties();
+            //注意对比Setup设置:Setup设置的属性,为属性赋新值后,调用属性值保持不变
 
+            // 设置并开始“跟踪”此属性
+            mock.SetupProperty(f => f.Name);
+
+            // 或者 设置默认值并开始“跟踪”此属性
             mock.SetupProperty(f => f.Name, "foo");
+
+            // 初始值被存储
             Assert.Equal("foo", ifoo.Name);
 
+            // 设定新值改,初始值被新值覆盖
+            ifoo.Name = "bar";
+            Assert.Equal("bar", ifoo.Name);
+        }
+
+        /// <summary>
+        /// 存根所有模拟属性
+        /// </summary>
+        [Fact]
+        public void Property_SetupAllProperties_Test()
+        {
+            mock //存根所有属性,这意味着设置其值将导致它被保存并在请求属性时返回。
+                 //每个属性值设置为Mock框架的默认值。
+                .SetupAllProperties();
+
+            Assert.Null(ifoo.Name);
+            
+            //赋新值
             ifoo.Name = "change";
             Assert.Equal("change", ifoo.Name);
         }
@@ -425,11 +551,10 @@ namespace MoqStudy.Test
         [Fact]
         public void Callback_Test()
         {
-            var mock = new Mock<IFoo>();
-            var ifoo = mock.Object;
             var calls = 0;
 
-            mock.Setup(foo => foo.DoSomething("ping"))
+            mock //回调函数,返回后,执行其它代码
+                .Setup(foo => foo.DoSomething("ping"))
                 .Returns(true)
                 .Callback(() => calls++);
 
@@ -447,20 +572,17 @@ namespace MoqStudy.Test
         }
 
         /// <summary>
-        /// access invocation arguments
-        /// 回调函数中使用参数
+        /// 回调函数中使用设置参数
         /// </summary>
         [Fact]
         public void Callback_Argument_Test()
         {
-            var mock = new Mock<IFoo>();
-            var ifoo = mock.Object;
             var callArgs = new List<string>();
-            //问题:多次设置,会什么结果
+
             mock.Setup(foo => foo.DoSomething(It.IsAny<string>()))
                 .Returns(true)
                 .Callback((string s) => callArgs.Add(s));
-            // 或者如下面泛型用法
+            // 或者如下:回调函数的泛型版本
             // .Callback<string>(s => callArgs.Add(s));
 
             Assert.True(ifoo.DoSomething("first"));
@@ -474,16 +596,13 @@ namespace MoqStudy.Test
         }
 
         /// <summary>
-        /// alternate equivalent generic method syntax
         /// 泛型回调函数中使用参数
         /// </summary>
         [Fact]
         public void Callback_Generic_Argument_Test()
         {
-            var mock = new Mock<IFoo>();
-            var ifoo = mock.Object;
             var callArgs = new List<string>();
-            //问题:多次设置,会什么结果
+
             mock.Setup(foo => foo.DoSomething(It.IsAny<string>()))
                 .Returns(true)
                 .Callback<string>(s => callArgs.Add(s));
@@ -499,15 +618,11 @@ namespace MoqStudy.Test
         }
 
         /// <summary>
-        ///  access arguments for methods with multiple parameters
         ///  回调函数中使用多个参数
         /// </summary>
         [Fact]
         public void Callback_MultiArgument_Test()
         {
-            var mock = new Mock<IFoo>();
-            var ifoo = mock.Object;
-
             var callCount = 0;
             var callArgs = new List<string>();
 
@@ -532,15 +647,11 @@ namespace MoqStudy.Test
         }
 
         /// <summary>
-        /// callbacks can be specified before and after invocation
         /// 指定回调函数位置:前置执行或后置执行
         /// </summary>
         [Fact]
         public void Callback_BeforeAndAfter_Test()
         {
-            var mock = new Mock<IFoo>();
-            var ifoo = mock.Object;
-
             var returnBefore = new List<string>();
             var returnAfter = new List<string>();
 
@@ -558,110 +669,125 @@ namespace MoqStudy.Test
         }
 
         /// <summary>
-        /// callbacks for methods with `ref` / `out` parameters are possible but require some work (and Moq 4.8 or later)
         /// 回调函数中使用 re/out 参数
         /// </summary>
         [Fact]
         public void Callback_RefAndOut_Parameter_Test()
         {
-            //var mock = new Mock<IFoo>();
-            //mock.Setup(foo => foo.Submit(ref It.Ref<Bar>.IsAny))
-            //   .Callback
-            //   (
-            //    new SubmitCallback
-            //    (
-            //        (ref Bar bar) => { bar.Baz.Name = "xyz"; }
-            //    )
-            //   );
-
-            //var myBar = new Bar()
-            //{
-            //    Baz=new Baz() { Name="gaofeng"}
-            //};
-
-            //mock.Object.Submit(ref myBar);
+            mock //回调函数中使用 re/out 参数
+                .Setup(foo => foo.Submit(ref It.Ref<Bar>.IsAny))
+               .Callback
+               (
+                    new SubmitCallback
+                    (
+                        (ref Bar bar) => { bar.Baz.Name = "xyz"; }
+                    )
+               );
+
+            var myBar = new Bar()
+            {
+                Baz = new Baz() { Name = "gaofeng" }
+            };
 
-            //Assert.Equal("xyz", myBar.Baz.Name);
+            mock.Object.Submit(ref myBar);
 
-            ////对比验证
-            //var mock2 = new Mock<IFoo>();
-            //mock2.Setup(foo => foo.Submit(ref It.Ref<Bar>.IsAny));
-            //var myBar2 = new Bar()
-            //{
-            //    Baz = new Baz() { Name = "gaofeng" }
-            //};
+            Assert.Equal("xyz", myBar.Baz.Name);
 
-            //mock2.Object.Submit(ref myBar2);
+            //和没有回调函数的对比验证
+            var mock2 = new Mock<IFoo>();
+            mock2.Setup(foo => foo.Submit(ref It.Ref<Bar>.IsAny));
+            var myBar2 = new Bar()
+            {
+                Baz = new Baz() { Name = "gaofeng" }
+            };
 
-            //Assert.Equal("gaofeng", myBar2.Baz.Name);
+            mock2.Object.Submit(ref myBar2);
 
+            Assert.Equal("gaofeng", myBar2.Baz.Name);
         }
         #endregion
 
         #region 验证
 
         /// <summary>
-        /// 不设置,进行验证,出现异常
+        /// 验证匹配项是否调用
+        /// 不设置,验证出现异常
         /// </summary>
         [Fact]
         public void Verify_NoSetup_Test()
         {
-            var mock = new Mock<IFoo>();
+            //验证匹配项是否调用
             Assert.Throws<MockException>(() => mock.Verify(f => f.Add(1)));
         }
 
         /// <summary>
-        /// 设置后,不运行方法进行验证
+        /// 验证匹配项是否调用
+        /// 设置后不运行,验证出现异常
         /// </summary>
         [Fact]
-        public void Verify_NoRun_Test()
+        public void Verify_Setup_NoRun_Test()
         {
-            var mock = new Mock<IFoo>();
-            var ifoo = mock.Object;
-            mock.Setup(f => f.Add(2)).Returns(true);
+            mock //验证匹配项是否调用
+                .Setup(f => f.Add(2))
+                .Returns(true);
 
             Assert.Throws<MockException>(() => { mock.Verify(f => f.Add(2)); });
         }
 
+        /// <summary>
+        /// 验证匹配项是否调用
+        /// 设置并调用后,验证通过
+        /// </summary>
         [Fact]
-        public void Verify_Test()
+        public void Verify_Setup_Test()
         {
-            var mock = new Mock<IFoo>();
-            var ifoo = mock.Object;
+            mock //设置
+                .Setup(f => f.Add(2))
+                .Returns(true);
 
-            mock.Setup(f => f.Add(2)).Returns(true);
+            //调用运行
             ifoo.Add(2);
+
+            //通过验证
             mock.Verify(f => f.Add(2));
         }
 
         /// <summary>
-        ///  Verify with custom error message for failure
-        ///  在验证失败的时候,提供自定义的错误提示信息 
+        ///  验证失败时,自定义异常信息 
         /// </summary>
         [Fact]
         public void Verify_ErrorMessage_Test()
         {
-            var mock = new Mock<IFoo>();
-            var ifoo = mock.Object;
-            Assert.Throws<MockException>(() => { mock.Verify(foo => foo.DoSomething("ping"), "When doing operation X, the service should be pinged always"); });
+            MockException mockException = null;
+            try
+            {
+                mock.Verify(foo => foo.DoSomething("ping"), "Custom exception message");
+                mockException = null;
+            }
+            catch (MockException ex)
+            {
+                mockException = ex;
+            }
+
+            Assert.StartsWith("Custom exception message", mockException.Message);
         }
 
         /// <summary>
-        /// Method should never be called
-        /// 方法从未被调用
+        /// 验证方法从未被调用
         /// </summary>
         [Fact]
         public void Verify_Never_Test()
         {
-            var mock = new Mock<IFoo>();
-            var ifoo = mock.Object;
-
             mock.Verify(foo => foo.DoSomething("ping"), Times.Never());
+
+            ifoo.DoSomething("ping");
+            Assert.Throws<MockException>(()=> {
+                mock.Verify(foo => foo.DoSomething("ping"), Times.Never());
+            });
         }
 
         /// <summary>
-        /// Called at least once
-        /// 至少调用过一次
+        /// 验证至少调用过一次
         /// </summary>
         [Fact]
         public void Verify_AtLeastOnce_Test()
@@ -701,7 +827,6 @@ namespace MoqStudy.Test
         }
 
         /// <summary>
-        /// Verify getter invocation, regardless of value
         /// 验证属性被读取过
         /// </summary>
         [Fact]
@@ -744,7 +869,6 @@ namespace MoqStudy.Test
         }
 
         /// <summary>
-        /// Verify setter invocation, regardless of value.
         /// 验证对属性的赋值(已弃用的方法)
         /// </summary>
         [Fact]
@@ -787,14 +911,11 @@ namespace MoqStudy.Test
         }
 
         /// <summary>
-        /// Verify setter invocation, regardless of value
         /// 验证对于属性设置特定的值
         /// </summary>
         [Fact]
         public void Verify_PropertieValue_Test()
         {
-            var mock = new Mock<IFoo>();
-            var ifoo = mock.Object;
             MockException mockException = null;
             var customInfo = "custom info";
             try
@@ -826,14 +947,11 @@ namespace MoqStudy.Test
         }
 
         /// <summary>
-        /// Verify setter with an argument matcher
         /// 验证匹配的参数
         /// </summary>
         [Fact]
         public void Verify_Propertie_Argument_Test()
         {
-            var mock = new Mock<IFoo>();
-            var ifoo = mock.Object;
             MockException mockException = null;
             var customInfo = "custom info";
             try
@@ -894,6 +1012,7 @@ namespace MoqStudy.Test
         ///  Callbase
         ///  使用Callbase
         ///  如果没有重写基类的实现,默认将不会调用基类,在 Mock Web/Html 控件的是必须的
+        ///  http://www.360doc.com/content/14/0729/09/10504424_397815601.shtml
         /// </summary>
         [Fact]
         public void CustomMock_Callbase_Test()