Ini pengontrol saya:
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 memiliki 2 dependensi, a IDAO
dan aILogger
Dan ini adalah kelas pengujian saya, saya menggunakan xUnit untuk menguji dan Moq untuk membuat tiruan dan rintisan, saya dapat mengejek dengan DAO
mudah, tetapi dengan ILogger
saya tidak tahu apa yang harus dilakukan jadi saya hanya memberikan null dan mengomentari panggilan untuk masuk pengontrol saat uji coba. Apakah ada cara untuk menguji tetapi tetap mempertahankan logger?
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());
}
}
ILogger
. Dia memiliki beberapa saran bagus di posting blognya dan saya telah datang dengan solusi saya yang tampaknya menyelesaikan sebagian besar masalah dalam jawaban di bawah ini .Jawaban:
Hanya mengejeknya serta ketergantungan lainnya:
Anda mungkin perlu menginstal
Microsoft.Extensions.Logging.Abstractions
paket untuk digunakanILogger<T>
.Selain itu, Anda dapat membuat logger nyata:
sumber
Sebenarnya, saya telah menemukan
Microsoft.Extensions.Logging.Abstractions.NullLogger<>
solusi yang tampaknya sempurna. Instal paketnyaMicrosoft.Extensions.Logging.Abstractions
, lalu ikuti contoh untuk mengkonfigurasi dan menggunakannya:dan uji unit
sumber
Gunakan logger khusus yang menggunakan
ITestOutputHelper
(dari xunit) untuk menangkap keluaran dan log. Berikut ini adalah contoh kecil yang hanya menulisstate
ke output.Gunakan di unittests Anda seperti
sumber
ILogger
akan membuatnya dapat digunakan secara lebih luas. 2)BeginScope
Seharusnya tidak kembali sendiri, karena itu berarti setiap metode yang diuji yang memulai dan mengakhiri cakupan selama proses akan membuang pencatat. Sebagai gantinya, buat kelas bertingkat "dummy" pribadi yang mengimplementasikanIDisposable
dan mengembalikan instance dari itu (lalu hapusIDisposable
dariXunitLogger
).Untuk jawaban .net core 3 yang menggunakan Moq
https://stackoverflow.com/a/56728528/2164198
tidak lagi berfungsi karena perubahan yang dijelaskan dalam masalah TState di ILogger.Log dulu objek, sekarang FormattedLogValues
Untungnya stakx memberikan solusi yang bagus . Jadi saya mempostingnya dengan harapan dapat menghemat waktu untuk orang lain (butuh beberapa saat untuk mencari tahu):
sumber
Menambahkan 2 sen saya, Ini adalah metode ekstensi pembantu yang biasanya dimasukkan ke dalam kelas pembantu statis:
Kemudian, Anda menggunakannya seperti ini:
Dan tentu saja Anda dapat dengan mudah memperluasnya untuk mengejek ekspektasi apa pun (mis. Ekspektasi, pesan, dll…)
sumber
ILogger
: gist.github.com/timabell/d71ae82c6f3eaa5df26b147f9d3842ebIt.Is<string>(s => s.Equals("A parameter is empty!"))
Sangat mudah karena jawaban lain menyarankan untuk melewatkan tiruan
ILogger
, tetapi tiba-tiba menjadi jauh lebih bermasalah untuk memverifikasi bahwa panggilan benar-benar dibuat ke logger. Alasannya adalah bahwa sebagian besar panggilan sebenarnya bukan milikILogger
antarmuka itu sendiri.Jadi, sebagian besar panggilan adalah metode ekstensi yang memanggil satu-satunya
Log
metode antarmuka. Alasannya tampaknya adalah jauh lebih mudah untuk membuat implementasi antarmuka jika Anda hanya memiliki satu dan tidak banyak kelebihan beban yang bermuara pada metode yang sama.Kekurangannya adalah tiba-tiba lebih sulit untuk memverifikasi bahwa panggilan telah dibuat karena panggilan yang harus Anda verifikasi sangat berbeda dari panggilan yang Anda buat. Ada beberapa pendekatan berbeda untuk mengatasi ini, dan saya telah menemukan bahwa metode ekstensi khusus untuk kerangka kerja tiruan akan membuatnya paling mudah untuk ditulis.
Berikut adalah contoh metode yang telah saya buat untuk dikerjakan
NSubstitute
:Dan inilah cara penggunaannya:
Tampaknya persis seperti jika Anda menggunakan metode secara langsung, triknya di sini adalah metode ekstensi kami mendapat prioritas karena "lebih dekat" dalam ruang nama daripada yang asli, jadi metode ekstensi akan digunakan sebagai gantinya.
Sayangnya itu tidak memberikan 100% apa yang kita inginkan, yaitu pesan kesalahan tidak akan sebaik, karena kita tidak memeriksa langsung pada string melainkan pada lambda yang melibatkan string, tetapi 95% lebih baik daripada tidak sama sekali :) Selain itu pendekatan ini akan membuat kode uji
PS Untuk MOQ satu dapat menggunakan pendekatan menulis metode ekstensi untuk
Mock<ILogger<T>>
yang melakukanVerify
untuk mencapai hasil yang sama.PPS Ini tidak berfungsi di .Net Core 3 lagi, periksa utas ini untuk detail lebih lanjut: https://github.com/nsubstitute/NSubstitute/issues/597#issuecomment-573742574
sumber
Sudah disebutkan, Anda dapat mengejeknya seperti antarmuka lainnya.
Sejauh ini baik.
Hal yang menyenangkan adalah Anda dapat menggunakan
Moq
untuk memverifikasi bahwa panggilan tertentu telah dilakukan . Misalnya di sini saya memeriksa bahwa log telah dipanggil dengan tertentuException
.Saat menggunakan
Verify
intinya adalah melakukannya melawanLog
metode nyata dariILooger
antarmuka dan bukan metode ekstensi.sumber
Membangun lebih jauh dari pekerjaan @ ivan-samygin dan @stakx, berikut adalah metode ekstensi yang juga bisa cocok dengan Exception dan semua nilai log (KeyValuePairs).
Ini bekerja (pada mesin saya;)) dengan .Net Core 3, Moq 4.13.0 dan Microsoft.Extensions.Logging.Abstractions 3.1.0.
sumber
Dan saat menggunakan StructureMap / Lamar:
Dokumen:
sumber
Hanya membuat boneka
ILogger
tidak terlalu berharga untuk pengujian unit. Anda juga harus memverifikasi bahwa panggilan logging telah dilakukan. Anda dapat menyuntikkan ejekanILogger
dengan Moq tetapi memverifikasi panggilan itu bisa sedikit rumit. Artikel ini membahas lebih dalam tentang memverifikasi dengan Moq.Berikut adalah contoh yang sangat sederhana dari artikel tersebut:
Ini memverifikasi bahwa pesan informasi telah dicatat. Tetapi, jika kita ingin memverifikasi informasi yang lebih kompleks tentang pesan seperti template pesan dan properti bernama, itu menjadi lebih rumit:
Saya yakin Anda dapat melakukan hal yang sama dengan kerangka kerja tiruan lainnya, tetapi
ILogger
antarmuka memastikan bahwa itu sulit.sumber
Jika masih aktual. Cara sederhana lakukan log ke output dalam pengujian untuk .net core> = 3
sumber
Gunakan Telerik Just Mock untuk membuat contoh logger yang diejek:
sumber
Saya telah mencoba untuk mengejek antarmuka Logger menggunakan NSubstitute (dan gagal karena
Arg.Any<T>()
memerlukan parameter tipe, yang tidak dapat saya berikan), tetapi akhirnya membuat logger percobaan (mirip dengan jawaban @ jehof) dengan cara berikut:Anda dapat dengan mudah mengakses semua pesan yang dicatat dan menegaskan semua parameter penting yang disediakan dengannya.
sumber