Dot-Net
無法實例化類的代理。找不到無參數建構子
在 .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(....//;