Pengaturan Moq untuk antarmuka dengan argumen fungsi

Saya ingin menulis UnitTest dengan Moq 4.14.7. Cara yang akan diuji adalah sebagai berikut:

public IFoo Get(Guid id)
{
    Func<IFoo> getData = () => _repository.Get(id);
    if (_cache.TryGetAndSet(vaultId, getData, out var result))
    {
        return result;
    }
}

Untuk menjelaskan secara singkat. Saya memiliki kelas cache generik. Ia memeriksa di cache apakah ada entitas dengan panduan yang diteruskan. Jika hal ini tidak terjadi, repositori akan dipanggil.

Sekarang saya memiliki pengaturan berikut untuk cache:

_cache.Setup
(
    x => x.TryGetAndSet
    (
        _vaultId,
        It.IsAny<Func<IFoo>>(),
        out foo
    )
)
.Returns(true);

Tes ini berhasil sejauh ini, namun saya tidak mencapai cakupan 100% karena fungsinya tidak tercakup.

Apakah ada cara yang lebih baik selain bekerja dengan It.IsAny dan mendapatkan cakupan 100%?


person BenGeba    schedule 18.01.2021    source sumber
comment
Tes itu mencakup 100% kode yang Anda tunjukkan. Apa artinya karena fungsinya tidak tercakup? Saya kira Anda memerlukan tes lain yang menghasilkan false?   -  person Liam    schedule 18.01.2021
comment
Tidak, dengan alat ReSharper UnitTestCoverage, hanya cakupan 88% yang tercapai dan fungsinya ditampilkan sebagai tidak tercakup.   -  person BenGeba    schedule 18.01.2021
comment
tapi bukankah fungsinya yang ingin kamu buat? Jadi mengapa hal itu harus ditutupi?   -  person HimBromBeere    schedule 18.01.2021
comment
Tanpa salinan alat ini saya tidak tahu apa yang dikeluhkannya. Jika Anda menambahkan tes lain yang menghasilkan false, apakah tes tersebut berhenti mengeluh? BTW cakupan kode 100% adalah omong kosong   -  person Liam    schedule 18.01.2021
comment
GetData-func asli Anda pasti tidak pernah dijalankan - dan karenanya tidak tercakup - karena Anda mengejek satu-satunya fungsi pemanggil - TryGetAndSet.   -  person HimBromBeere    schedule 18.01.2021
comment
@HimBromBeere jika saya melakukan _repo.Setup(x => x.Get(id)).Returns(It.IsAny<IFoo>); sebelumnya, masih tidak dipanggil, karena saya memiliki It.IsAny<Func<IFoo>>() di cache tiruan.   -  person BenGeba    schedule 18.01.2021
comment
@Liam Tidak, sayangnya masih mengeluh.   -  person BenGeba    schedule 18.01.2021
comment
delegasi tidak akan pernah dieksekusi, karena satu-satunya fungsi yang memanggilnya akan diolok-olok. Pada dasarnya Anda mengatakan: ganti setiap panggilan ke TryGetAndSet dengan sesuatu yang benar-benar berbeda yang tidak akan pernah menyentuh delegasi sama sekali.   -  person HimBromBeere    schedule 18.01.2021
comment
Saya juga telah mencoba tiruan cache alih-alih It.IsAny<> a () => _repository.Setup(m => m.Get(id)).Returns(foo) tetapi mengharapkan IFoo sebagai nilai kembalian, tetapi mendapat repo.   -  person BenGeba    schedule 18.01.2021


Jawaban (1)


Tangkap argumen yang diteruskan ke anggota dan aktifkan fungsi sesuai keinginan.

//...

IFoo mockedFoo = Mock.Of<IFoo>();

IFoo foo = null;

_repo.Setup(_ => _.Get(It.IsAny<Guid>()).Returns(mockedFoo);

_cache
    .Setup(_ => _.TryGetAndSet(It.IsAny<Guid>(), It.IsAny<Func<IFoo>>(), out foo))
    .Returns((Guid vid, Func<IFoo> func, IFoo f) => {
        foo = func(); //<-- invoke the function and assign to out parameter.
        return true;
    });

//...

//Assertion can later verify that the repository.Get was invoked
//Assertion can later assert that foo equals mockedFoo

TryGetAndSet akan mengembalikan true, dan argumen keluar akan mengembalikan mockedFoo, yang malas dievaluasi

Referensi Mulai Cepat Moq

person Nkosi    schedule 18.01.2021
comment
Terima kasih, itu berhasil dengan baik :) - person BenGeba; 18.01.2021