簡體   English   中英

mocking 外部 DLL 使用 C# 中的起訂量進行單元測試

[英]Unit test by mocking external DLL using Moq in C#

我正在嘗試為我的一個函數編寫一個單元測試,該函數依賴於外部 DLL。 我決定使用 Moq(模擬外部依賴)來測試我的 function。

MyClass 有一個 function 和一個外部依賴項。

namespace MyService
{
    /// <summary>
    /// MyClass
    /// </summary>
    public class MyClass : IMyClass
    {
        private ExternalClass ex;
        public MyClass() {
            ex = new ExternalClass();
        }
        public bool publish(string param) {
           if(... param is not valid)
              throw error;
           return ex.externalPublish(param);
        }
    }
}

外部 class 發布 function 調用一些運行時依賴項,因此不能期望 function 在單元測試期間運行


namespace ExternalService
{
    /// <summary>
    /// ExternalClass
    /// </summary>
    public class ExternalClass : IExternalClass, OtherExternalClass // OtherExternalClass is a concrete one, not an interface
    {
        public ExternalClass(){}

        public bool publish(string param) {
           // some implementation which contacts database, other running services etc.
        }
    }
}
namespace MyServiceTests
{
    using Moq;
     /// <summary>
    /// MyClass test
    /// </summary>
    [TestClass]
    public class MyClassTest
    {
      
        /// <summary>
        /// Publish
        /// </summary>
        [TestMethod]
        public void PublishTestSucceed()
        {
            var moq = new Mock<ExternalClass>(); // I tried IExternalClass but it is not the only inheritence that ExternalClass has.
            moq.CallBase = true;
            moq.Setup(tsmv2 => tsmv2.publish(
                It.IsAny<string>()))
                .Returns(true);


            MyClass myC = new MyClass();
            PrivateObject obj = new PrivateObject(myC);

            obj.SetField("ex", moq.Object); // If I use IExternalClass to create moq, I am not able to convert IExternalClass to ExternalClass here.

            bool result = myC.publish("asdf");
            Assert.IsTrue(result);
        }

所以有兩個問題:

  1. 外部 class 並不完全依賴於一個接口。 我還能在這里使用 Moq 庫嗎?
  2. 即使我使用該接口,我也無法將moq.Object轉換為 IExternalClass object,即使使用顯式轉換也是如此。

被測對象與具體的外部實現細節緊密耦合,並且應該依賴於通過構造函數注入使用顯式依賴原則的抽象。

重構主題 class:

public class MyClass : IMyClass {
    private IExternalClass ex;

    public MyClass(IExternalClass ex) {
        this.ex = ex;
    }

    public bool publish(string param) {
       if(... param is not valid)
          throw error;
       return ex.publish(param); //... external call
    }
}

對於主題 class 來說,依賴關系是外部的,這真的無關緊要。 那是一個實現細節。

現在,這允許主題 class 明確說明執行其 function 所需的內容,並且通過依賴抽象允許使用替代品。 例如,在隔離測試時。

[TestClass]
public class MyClassTest {
  
    public void PublishTestSucceed() {
        // Arrange
        var dependency = new Mock<IExternalClass>();
        dependency
            .Setup(_ => _.publish(It.IsAny<string>()))
            .Returns(true);

        MyClass myC = new MyClass(dependency.Object);

        //Act
        bool result = myC.publish("asdf");

        //Assert
        Assert.IsTrue(result);
    }
}

如果顯式使用IExternalClass作為依賴項有太多限制,請考慮使用封裝/包裝外部依賴項功能的實現創建自己的抽象。

這樣您就可以更好地控制您的代碼,並且不受您無法控制的依賴項限制的限制。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM