Saya menulis tes yang bergantung pada hasil metode ekstensi tetapi saya tidak ingin kegagalan metode ekstensi itu di masa mendatang untuk merusak tes ini. Mengolok-olok hasil itu tampaknya merupakan pilihan yang jelas tetapi Moq tampaknya tidak menawarkan cara untuk menimpa metode statis (persyaratan untuk metode ekstensi). Ada ide serupa dengan Moq.Protected dan Moq.Stub, tetapi mereka tampaknya tidak menawarkan apa pun untuk skenario ini. Apakah saya melewatkan sesuatu atau haruskah saya melakukannya dengan cara yang berbeda?
Berikut adalah contoh sepele yang gagal dengan "Harapan tidak valid pada anggota yang tidak dapat diganti" yang biasa . Ini adalah contoh buruk dari perlunya mengejek metode ekstensi, tetapi seharusnya begitu.
public class SomeType {
int Id { get; set; }
}
var ListMock = new Mock<List<SomeType>>();
ListMock.Expect(l => l.FirstOrDefault(st => st.Id == 5))
.Returns(new SomeType { Id = 5 });
Adapun setiap pecandu TypeMock yang mungkin menyarankan saya menggunakan Isolator sebagai gantinya: Saya menghargai upaya karena sepertinya TypeMock dapat melakukan pekerjaan itu dengan mata tertutup dan mabuk, tetapi anggaran kami tidak meningkat dalam waktu dekat.
sumber
Jawaban:
Metode ekstensi hanyalah metode statis yang disamarkan. Kerangka kerja tiruan seperti Moq atau Rhinomocks hanya dapat membuat contoh objek tiruan, ini berarti metode statis tiruan tidak dimungkinkan.
sumber
Jika Anda dapat mengubah kode metode ekstensi maka Anda dapat mengkodekannya seperti ini untuk dapat menguji:
using System; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; public static class MyExtensions { public static IMyImplementation Implementation = new MyImplementation(); public static string MyMethod(this object obj) { return Implementation.MyMethod(obj); } } public interface IMyImplementation { string MyMethod(object obj); } public class MyImplementation : IMyImplementation { public string MyMethod(object obj) { return "Hello World!"; } }
Jadi metode ekstensi hanyalah pembungkus di sekitar antarmuka implementasi.
(Anda dapat menggunakan hanya kelas implementasi tanpa metode ekstensi yang semacam gula sintaksis.)
Dan Anda dapat membuat tiruan antarmuka implementasi dan menetapkannya sebagai implementasi untuk kelas ekstensi.
public class MyClassUsingExtensions { public string ReturnStringForObject(object obj) { return obj.MyMethod(); } } [TestClass] public class MyTests { [TestMethod] public void MyTest() { // Given: //------- var mockMyImplementation = new Mock<IMyImplementation>(); MyExtensions.Implementation = mockMyImplementation.Object; var myClassUsingExtensions = new MyClassUsingExtensions(); // When: //------- var myObject = new Object(); myClassUsingExtensions.ReturnStringForObject(myObject); //Then: //------- // This would fail because you cannot test for the extension method //mockMyImplementation.Verify(m => m.MyMethod()); // This is success because you test for the mocked implementation interface mockMyImplementation.Verify(m => m.MyMethod(myObject)); } }
sumber
Saya tahu pertanyaan ini belum aktif selama sekitar satu tahun tetapi Microsoft merilis kerangka kerja untuk menangani persis ini yang disebut Moles .
Berikut beberapa tutorialnya juga:
sumber
Saya membuat kelas pembungkus untuk metode ekstensi yang perlu saya tiru.
public static class MyExtensions { public static string MyExtension<T>(this T obj) { return "Hello World!"; } } public interface IExtensionMethodsWrapper { string MyExtension<T>(T myObj); } public class ExtensionMethodsWrapper : IExtensionMethodsWrapper { public string MyExtension<T>(T myObj) { return myObj.MyExtension(); } }
Kemudian Anda dapat memalsukan metode pembungkus dalam pengujian dan kode dengan penampung IOC Anda.
sumber
Untuk metode penyuluhan saya biasanya menggunakan pendekatan berikut:
public static class MyExtensions { public static Func<int,int, int> _doSumm = (x, y) => x + y; public static int Summ(this int x, int y) { return _doSumm(x, y); } }
Ini memungkinkan untuk menyuntikkan _doSumm dengan cukup mudah.
sumber
Hal terbaik yang dapat Anda lakukan adalah menyediakan implementasi kustom untuk jenis yang memiliki metode ekstensi, misalnya:
[Fact] public class Tests { public void ShouldRunOk() { var service = new MyService(new FakeWebHostEnvironment()); // Service.DoStuff() internally calls the SomeExtensionFunction() on IWebHostEnvironment // Here it works just fine as we provide a custom implementation of that interface service.DoStuff().Should().NotBeNull(); } } public class FakeWebHostEnvironment : IWebHostEnvironment { /* IWebHostEnvironment implementation */ public bool SomeExtensionFunction() { return false; } }
sumber