Dot-Net

無法實例化類的代理。找不到無參數建構子

  • July 21, 2021

在 .Net Core 中使用 xUnit 和 Moq 編寫測試案例時,我面臨著突出的問題

我已經使用 MSTest Fakes 編寫了下面的測試案例。它按預期工作正常。

[TestClass]
public class TestBlobServiceProvider
{
   private Common.Interfaces.IBlobServiceProvider _iblobprovider;

   public TestBlobServiceProvider()
   {
       Common.Interfaces.IBlobServiceProvider iblobprovider = new BlobServiceProvider();
       this._iblobprovider = iblobprovider;
   }

   public TestBlobServiceProvider(string storageConnectionString)
   { 

   }


   [TestMethod]
   public void Move_Success()
   {
       using (ShimsContext.Create())
       {
           string sourceContainer = "a";
           string destinationContainer = "s";
           string sourceFileName = "d";
           string destinationFileName = "e";

           Microsoft.WindowsAzure.Storage.Blob.Fakes.ShimCloudBlockBlob sourceFile = new Microsoft.WindowsAzure.Storage.Blob.Fakes.ShimCloudBlockBlob ();
           Microsoft.WindowsAzure.Storage.Blob.Fakes.ShimCloudBlockBlob destFile = new Microsoft.WindowsAzure.Storage.Blob.Fakes.ShimCloudBlockBlob();

           Microsoft.WindowsAzure.Storage.Blob.Fakes.ShimCloudBlockBlob.AllInstances.StartCopyCloudBlockBlobAccessConditionAccessConditionBlobRequestOptionsOperationContext = (x, y, z, d, e,s) =>
           { 
                    return "Hi"; 
           };

           Microsoft.WindowsAzure.Storage.Blob.Fakes.ShimCloudBlob.AllInstances.DeleteDeleteSnapshotsOptionAccessConditionBlobRequestOptionsOperationContext = (x, y, z, d, e) =>
          {

          };

           Microsoft.WindowsAzure.Storage.Blob.Fakes.ShimCloudBlobClient.AllInstances.GetContainerReferenceString = (x, y) =>
           {
               return new Microsoft.WindowsAzure.Storage.Blob.Fakes.ShimCloudBlobContainer();
           };

           Microsoft.WindowsAzure.Storage.Blob.Fakes.ShimCloudBlobContainer.AllInstances.CreateIfNotExistsAsync = (x) =>
           {
               return Task.Run(() =>
               {
                  return new bool();
               });
           };

           Microsoft.WindowsAzure.Storage.Blob.Fakes.ShimCloudBlobContainer.AllInstances.GetBlockBlobReferenceString = (x, y) =>
           {
               return new Microsoft.WindowsAzure.Storage.Blob.Fakes.ShimCloudBlockBlob();

           };


           CDM.Common.Fakes.ShimBlobServiceProvider.AllInstances.GetBlockBlobContainerString = (x, y) =>
           {
               return new Microsoft.WindowsAzure.Storage.Blob.Fakes.ShimCloudBlobContainer();
           };

           this._iblobprovider.Move( sourceContainer,  destinationContainer,  sourceFileName,  destinationFileName);

       }

   }
}

但是現在我們需要遷移到 .Net Core 。因此,我開始使用 xUnit 測試案例,因為 .Net 核心缺少 Fakes 支持。

下面的程式碼是 xUnit 和 Moq

public class TestBlobServiceProvider
{
   private readonly Common.Interfaces.IBlobServiceProvider _iblobprovider;

   public TestBlobServiceProvider()
   {
       Common.Interfaces.IBlobServiceProvider iblobprovider = new BlobServiceProvider();
       this._iblobprovider = iblobprovider;
   }

   [Fact]
   public void Move_Success()
   {
           string sourceContainer = "a";
           string destinationContainer = "s";
           string sourceFileName = "d";
           string destinationFileName = "e";

           var uri = new Uri("https://app.blob.core.windows.net/container/https://app.blob.core.windows.net/container/Accounts/Images/acc.jpg");

           CloudBlockBlob source = null;
           AccessCondition sourceAccessCondition = null;
           AccessCondition destAccessCondition = null;
           BlobRequestOptions options = null;
           OperationContext operationContext = null;
           CloudBlobContainer container = new CloudBlobContainer (uri);
           Task task = null;
           DeleteSnapshotsOption deleteSnapshotsOption = new DeleteSnapshotsOption();


           var mockCloudBlobClient = new Mock<Microsoft.WindowsAzure.Storage.Blob.CloudBlobClient>();
           mockCloudBlobClient.Setup(repo => repo.GetContainerReference("sample")).Returns(container);

           var mockCloudBlobContainer = new Mock<Microsoft.WindowsAzure.Storage.Blob.CloudBlobContainer>();
           mockCloudBlobContainer.Setup(repo => repo.GetBlockBlobReference("sample")).Returns(new CloudBlockBlob(uri));

           mockCloudBlobContainer.Setup(repo => repo.CreateIfNotExistsAsync()).Returns(Task.Run(() =>
           {
               return new bool();
           }));


          var mockCloudBlob = new Mock<Microsoft.WindowsAzure.Storage.Blob.CloudBlob>();
           mockCloudBlob.Setup(repo => repo.DeleteAsync(deleteSnapshotsOption, sourceAccessCondition, options, operationContext)).Returns(task);

           var mockCloudBlockBlob = new Mock<Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob>();
           mockCloudBlockBlob.Setup(repo => repo.StartCopyAsync(source, sourceAccessCondition, destAccessCondition, options, operationContext)).ReturnsAsync("Hi");

           Common.Interfaces.IBlobServiceProvider obj = new BlobServiceProvider(mockCloudBlobClient.Object, mockCloudBlobContainer.Object, mockCloudBlob.Object, mockCloudBlockBlob.Object);

           obj.Move(sourceContainer, destinationContainer, sourceFileName, destinationFileName);

       //   this._iblobprovider.Move(sourceContainer, destinationContainer, sourceFileName, destinationFileName);

   }
}

我收到錯誤

Common.Interfaces.IBlobServiceProvider obj = new BlobServiceProvider(mockCloudBlobClient.Object, mockCloudBlobContainer.Object, mockCloudBlob.Object, mockCloudBlockBlob.Object);`

錯誤:

無法實例化類代理:Microsoft.WindowsAzure.Storage.Blob.CloudBlobClient。找不到無參數建構子。

如何解決上述問題

問題是**moq無法創建CloudBlobClient,因為它沒有無參數建構子。但是moq**能夠在沒有無參數建構子的情況下創建對象,但您需要提供參數。

最簡單的方法是使用這個建構子

public CloudBlobClient (
   Uri baseUri, System.Net.Http.DelegatingHandler delegatingHandler = null);

並提供Uri.

就像是:

var mockCloudBlobClient = new Mock<CloudBlobClient>(new Uri("http://mytest"));

當您模擬實現而不是介面時,經常會出現這種情況。如果一個對像有一個介面,通常模擬該介面會容易得多。

例如,想像一下這個工人階級:

//worker.cs
public class TemplateWorker : ITemplateWorker
   {
       private readonly ITemplateRetriever templateRetriever;
       
       public TemplateWorker(ITemplateRetriever templateRetriever)
       {
           this.templateRetriever = templateRetriever ?? 
              throw new ArgumentNullException(nameof(templateRetriever));
       }
    //..class body
    }

如果你試圖模擬這個,你會在這篇文章中得到錯誤

tests.cs
var mockWorker = Mock.Of<TemplateWorker>();
//!!Can not instantiate proxy of class TestProject.TemplateWorker : 
//!!  Could not find a parameterless constructor.'

但是,如果我改為模擬界面……沒有錯誤!這很好,因為在模擬的大部分時間裡,我們只關心這個類如何使用其依賴項的公共契約中的項目。

var mockWorker = Mock.Of<ITemplateWorker>();

//setup what should happen when I call its method...
Mock.Get(mockWorker).Setup(x=>x.SomeMethod(....//;

引用自:https://stackoverflow.com/questions/56989674