本文

比對兩個物件方式

首先我們建立一個測試用 Model。

    public class TestModel
    {
        public string UserName { get; set; }

        public string Account { get; set; }
    }

建立一個測試方法驗證兩個物件是否相同。

        [TestMethod()]
        [Owner("Sian")]
        [TestCategory("Class1")]
        [TestProperty("Class1", "Object")]
        public void ObjectTest_比較兩個相同物件_應回傳正確結果()
        {
            //arrange 
            var fistObject = new TestModel
            {
                Account = "abc",
                UserName = "Sian"
            };

            var secondObject = new TestModel
            {
                Account = "abc",
                UserName = "Sian"
            };

            secondObject.Should().Be(fistObject);
        }

結果

有點奇怪,我們換回內建的方法測試看看。

        [TestMethod()]
        [Owner("Sian")]
        [TestCategory("Class1")]
        [TestProperty("Class1", "Object")]
        public void ObjectTest_比較兩個相同物件_應回傳正確結果()
        {
            //arrange 
            var fistObject = new TestModel
            {
                Account = "abc",
                UserName = "Sian"
            };

            var secondObject = new TestModel
            {
                Account = "abc",
                UserName = "Sian"
            };

            //secondObject.Should().Be(fistObject);
            //Assert.AreEqual(fistObject,secondObject);
            Assert.AreSame(fistObject, secondObject);
        }

還是一樣錯誤。

方法 定義
AreSame() 比較兩個物件的記憶體位址是否一致。
AreEqual() AreEqual 則是繼承了原本 Object 使用的 Equals,也是比較記憶體位址。

所以如果要解決此種情況,就只能複寫原本的 AreEqual() 方法,所以基於懶惰原則,當然是另尋出路。

Fluentassertion 有提供這個方法比較,我們來測試看看。

        [TestMethod()]
        [Owner("Sian")]
        [TestCategory("Class1")]
        [TestProperty("Class1", "Object")]
        public void ObjectTest_比較兩個相同物件_應回傳正確結果()
        {
            //arrange 
            var fistObject = new TestModel
            {
                Account = "abc",
                UserName = "Sian"
            };

            var secondObject = new TestModel
            {
                Account = "abc",
                UserName = "Sian"
            };

            //secondObject.Should().Be(fistObject);
            //Assert.AreEqual(fistObject,secondObject);
            //Assert.AreSame(fistObject, secondObject);
            secondObject.Should().BeEquivalentTo(fistObject);
        }

結果

比對兩個集合方式

一樣也可以透過 BeEquivalentTo 這個方法驗證。

        [TestMethod()]
        [Owner("Sian")]
        [TestCategory("Class1")]
        [TestProperty("Class1", "CollectionTest")]
        public void CollectionTest_比較兩個集合_應回傳正確結果()
        {
            //arrange 
            var fistCollection = new List<TestModel>
            {
                new TestModel
                {
                    Account = "abc",
                    UserName = "Sian"
                }
            };

            var secondCollection = new List<TestModel>
            {
                new TestModel
                {
                    Account = "abc",
                    UserName = "Sian"
                }
            };

            secondCollection.Should().BeEquivalentTo(fistCollection);
        }

結果

時間測試方法

首先我們建立一個會用到時間的方法。

        public string GetNewYear()
        {
            if (DateTime.Now.Month == 1 &&
                DateTime.Now.Day == 1)
            {
                return "Happy NEW YEAR!";
            }

            return "Today is not Holiday";
        }

測試方法

        [TestMethod()]
        [Owner("Sian")]
        [TestCategory("Class1")]
        [TestProperty("Class1", "GetNewYear")]
        public void GetNewYear_若今天不是新年_應回傳提示訊息()
        {
            //arrange
            var target = new Class1();
            var expected = "Today is not Holiday";

            //act
            var actual = target.GetNewYear();

            //assert
            actual.Should().Be(expected);
        }

結果

現在我們遇到了一個問題,因為時間的關係,我們並不能測試如果是1/1的話是否會正確顯示提示訊息。

這時候我們可以自己撰寫一個擴充方法。

    public static class SystemTime
    {
        internal static Func<DateTime> SetCurrentTime = () => DateTime.Now;

        internal static Func<DateTime> SetToday = () => DateTime.Today;

        public static DateTime Now => SetCurrentTime();

        public static DateTime Today => SetToday();
    }

接下來把 DateTime 改成使用 SystemTime。

        public string GetNewYear()
        {
            if (SystemTime.Today.Month == 1 &&
                SystemTime.Today.Day == 1)
            {
                return "Happy NEW YEAR!";
            }

            return "Today is not Holiday";
        }

接下來為了讓測試專案可以改變 Internal 屬性,需要到 AssemblyInfo.cs 加入東西。
先切換成資料夾檢視。

為了要看到 AssemblyInfo.cs 需要先把顯示所有檔案打開。

搜尋 AssemblyInfo。

有 Debug 版本以及 Release 版本,兩個都要記得修改。
加入以下程式碼。

[assembly: InternalsVisibleTo("UnitTestProject")]

接著修改儲存完回到我們的測試。

        [TestMethod()]
        [Owner("Sian")]
        [TestCategory("Class1")]
        [TestProperty("Class1", "GetNewYear")]
        public void GetNewYear_若今天是新年_應回傳提示訊息()
        {
            //arrange
            var target = new Class1();
            var expected = "Happy NEW YEAR!";

            SystemTime.SetToday = () => new DateTime(year:2021,month:1,day:1);

            //act
            var actual = target.GetNewYear();

            //assert
            actual.Should().Be(expected);
        }

結果:

參考連結