Lebih
Bagaimana untuk unit test dengan ILogger di ASP.NET Inti
Ini adalah controller:
public class BlogController : Controller
{
private IDAO<Blog> _blogDAO;
private readonly ILogger<BlogController> _logger;
public BlogController(ILogger<BlogController> logger, IDAO<Blog> blogDAO)
{
this._blogDAO = blogDAO;
this._logger = logger;
}
public IActionResult Index()
{
var blogs = this._blogDAO.GetMany();
this._logger.LogInformation("Index page say hello", new object[0]);
return View(blogs);
}
}
Seperti yang anda lihat saya punya 2 ketergantungan, IDAO
dan ILogger
Dan ini adalah tes saya di kelas, saya menggunakan xUnit untuk menguji dan Moq untuk membuat mock dan rintisan, aku bisa pura-pura DAO
mudah, tapi dengan ILogger
I don't tahu apa yang harus dilakukan jadi saya hanya lulus null dan komentar call log in controller ketika menjalankan tes. Apakah ada cara untuk menguji tapi masih tetap logger entah bagaimana ?
public class BlogControllerTest
{
[Fact]
public void Index_ReturnAViewResult_WithAListOfBlog()
{
var mockRepo = new Mock<IDAO<Blog>>();
mockRepo.Setup(repo => repo.GetMany(null)).Returns(GetListBlog());
var controller = new BlogController(null,mockRepo.Object);
var result = controller.Index();
var viewResult = Assert.IsType<ViewResult>(result);
var model = Assert.IsAssignableFrom<IEnumerable<Blog>>(viewResult.ViewData.Model);
Assert.Equal(2, model.Count());
}
}
82
8
Hanya pura-pura itu serta lain ketergantungan:
Anda mungkin akan perlu menginstal
Microsoft.Ekstensi.Logging.Abstraksi
paket untuk menggunakanILogger<T>
.Selain itu anda dapat membuat nyata logger:
Sebenarnya, aku've ditemukan
Microsoft.Ekstensi.Logging.Abstraksi.NullLogger<>
yang tampak seperti solusi yang sempurna.Menggunakan custom logger yang menggunakan
ITestOutputHelper
(dari xunit) untuk menangkap output dan log. Berikut adalah sebuah contoh kecil yang hanya menulisnegara
untuk output.Menggunakannya dalam unittests seperti
Menambahkan saya 2 sen, Ini adalah penolong metode penyuluhan biasanya dimasukkan ke dalam statis kelas helper: `` statis kelas MockHelper { public static ISetup<ILogger> MockLog(Mock<ILogger> logger, LogLevel tingkat) { kembali logger.Setup(x => x.Log(level Itu.IsAny(), Hal.IsAny<objek>(), Hal.IsAny(), Hal.IsAny<Func<objek, Pengecualian, string>>())); }
pribadi statis Ekspresi<Action<ILogger>> Verifikasi(LogLevel tingkat) { kembali x => x.Log(level, 0, Hal.IsAny<objek>(), Hal.IsAny(), Hal.IsAny<Func<objek, Pengecualian, string>>()); }
public static void Verifikasi(Mock<ILogger> pura-pura, LogLevel tingkat, Kali kali) { mengejek.Memverifikasi(Verify(tingkat), kali); } }
Kemudian, anda dapat menggunakannya seperti ini:
//Mengatur var logger = new Mock<ILogger>(); logger.MockLog(LogLevel.Warning)//Bertindak
//Menyatakan logger.Verifikasi(LogLevel.Peringatan, Kali.Setelah()); `` Dan tentu saja anda dapat dengan mudah memperpanjang mengejek harapan (yaitu expection, pesan, dll ...)
Sudah disebutkan, anda bisa pura-pura itu sebagai antarmuka lainnya.
Sejauh ini baik-baik.
Hal yang baik adalah bahwa anda dapat menggunakan
Moq
ke pastikan bahwa panggilan tertentu yang telah dilakukan. Untuk contoh di sini saya periksa log telah disebut denganPengecualian
.Ketika menggunakan
Verifikasi
intinya adalah untuk melakukan itu melawan realLog
metode `ILooger antarmuka dan bukan metode ekstensi.Hal ini mudah karena jawaban yang lain menyarankan untuk melewati pura-pura
ILogger
, tapi itu tiba-tiba menjadi jauh lebih bermasalah untuk memverifikasi bahwa panggilan benar-benar dibuat untuk logger. Alasannya adalah bahwa sebagian besar panggilan tidak benar-benar milikILogger
antarmuka itu sendiri.Sehingga semua panggilan adalah metode ekstensi panggilan itu hanya
Log
metode antarmuka. Alasan itu tampaknya adalah bahwa hal itu's cara yang lebih mudah untuk membuat implementasi antarmuka jika anda memiliki hanya satu dan tidak banyak overloads yang bermuara pada metode yang sama.Kelemahan ini tentu saja bahwa itu adalah tiba-tiba jauh lebih sulit untuk memverifikasi bahwa panggilan telah dibuat sejak panggilan anda harus memverifikasi sangat berbeda dari panggilan yang anda buat. Ada beberapa pendekatan yang berbeda untuk bekerja di sekitar ini, dan saya telah menemukan bahwa ekstensi kustom metode untuk mengejek framework akan membuat lebih mudah untuk menulis.
Berikut ini adalah contoh dari metode yang saya telah dibuat untuk bekerja dengan
NSubstitute
:Dan ini adalah bagaimana hal itu dapat digunakan:
Hal ini terlihat persis seperti jika anda menggunakan metode langsung, kuncinya di sini adalah bahwa metode penyuluhan mendapat prioritas karena itu's "lebih" di namespaces daripada yang asli, sehingga akan digunakan sebagai gantinya.
Itu tidak memberikan sayangnya 100% apa yang kita inginkan, yaitu pesan kesalahan tidak akan menjadi baik, karena kita don't cek langsung pada string melainkan pada lambda yang melibatkan string, tapi 95% lebih baik dari apa-apa :) Selain itu pendekatan ini akan membuat kode tes
P. S. Untuk Moq satu dapat menggunakan pendekatan penulisan perpanjangan metode untuk
Mengejek<ILogger<T>>
yang melakukanVerifikasi
untuk mencapai hasil yang sama.Dan ketika menggunakan StructureMap / Lamar:
Docs:
Untuk .net core 3 jawaban yang menggunakan Moq
tidak lagi bekerja karena perubahan yang dijelaskan dalam masalah Tkondisi di ILogger.Log digunakan untuk menjadi objek, sekarang FormattedLogValues
Lickily stakx yang disediakan bagus pemecahan masalah. Jadi saya'm postingan ini di harapkan dapat menghemat waktu untuk orang lain (butuh beberapa saat untuk mencari hal-hal yang keluar):
loggerMock.Verifikasi( x => x.Log( LogLevel.Informasi, Itu.IsAny<Pemberi>(), Itu.Adalah<Hal.IsAnyType>((o, t) => string.Sama dengan("halaman Indeks say hello", o.ToString(), StringComparison.InvariantCultureIgnoreCase)), Itu.IsAny<Pengecualian>(), (Func<Hal.IsAnyType, Pengecualian, string>) Itu.IsAny<objek>()), Kali.Sekali);