Moq: Penyiapan tidak valid pada anggota yang tidak dapat diganti: x => x.GetByTitle ("asdf")

111

Tidak yakin bagaimana saya bisa memperbaikinya, mencoba melakukan tes unit pada metode "GetByTitle"

Inilah definisi saya:

public class ArticleDAO :  GenericNHibernateDAO(IArticle, int>, IArticleDAO
{
    public IArticle GetByTitle(string title)
    {
        IQuery query = Session.CreateQuery("...")
        return query.UniqueResult<IArticle>();
    }
}

public interface IArticleDAO
{
    IArticle GetByTitle(string title);
}

tes unit:

[Test]
public void can_load_by_title()
{
    _mockDaoFactory.Setup(x => x.GetArticleDao())
                                .Returns(_mockArticleDao.Object);
    _mockArticleDao.Setup(x => x.GetByTitle("some title"))
                                .Returns(article1.Object);

    _articleManager.LoadArticle("some title");

    Assert.IsNotNull(_articleManager.Article);
}

Menjalankan tes memberi saya kesalahan:

System.ArgumentException: Invalid setup on a non-overridable member:
x => x.GetByTitle("some title")

Memperbarui

Saya [Setup]terlihat seperti:

[Setup]
public void SetUp()
{
     _mockDaoFactory = new Mock<IDaoFactory>();
     _mockArticleDao = new Mock<ArticleDao>();

     _articleManager = new ArticleManager(_mockDaoFactory.Object);    
}
mrblah
sumber
2
Apakah Anda memberi contoh _mockDaoFactorydan di _mockArticleDaosuatu tempat? Apakah Anda mengejek kelas atau antarmuka
Tomas Aschan
Ya saya mengejek daofactory dan mockarticleDao di [Setup] menggunakan Interface. DAO dilakukan dengan menggunakan kelas.
mrblah
@tomas Saya memperbarui pertanyaan saya dengan kode pengaturan.
mrblah
2
Seperti yang Anda lihat di jawaban saya, Anda perlu mengejek antarmuka (itulah yang saya rekomendasikan) atau menandai GetByTitlemetode virtual.
Tomas Aschan
Ini juga terlihat seolah-olah baris pertama dalam pengujian Anda dapat dipindahkan ke rutinitas penyiapan ...?
Tomas Aschan

Jawaban:

154

Untuk mengontrol perilaku objek tiruan (setidaknya dalam Moq), Anda perlu meniru antarmuka, atau memastikan bahwa perilaku yang Anda coba kontrol ditandai virtual. Dalam komentar Anda, saya memahaminya sehingga pembuatan instance _mockArticleDaodilakukan seperti ini:

_mockArticleDao = new Mock<ArticleDAO>();

Jika Anda ingin menyimpannya seperti itu, Anda perlu menandai GetArticlemetode virtual:

public class ArticleDAO :  GenericNHibernateDAO(IArticle, int>, IArticleDAO
{
    public virtual IArticle GetByTitle(string title)
    {
        // ...
    }
}

Jika tidak (dan inilah yang saya rekomendasikan), tirulah antarmuka sebagai gantinya.

_mockArticleDao = new Mock<IArticleDAO>();
Tomas Aschan
sumber
tetapi karena ArticleDAO mewarisi dari Generic ...., jika saya mengejek antarmuka metode di GenericNhibern. tidak akan tersedia?
mrblah
karena panggilan ke GetArticleDAO dari pabrik mengembalikan ArticleDAO bukan IArticleDAO, b / c articleDAO juga mengikat ke kelas abstrak yang memiliki hal-hal nhibernate di dalamnya.
mrblah
2
Jika Anda tidak dapat mengejek antarmuka, maka Anda mungkin menguji hal yang salah ... tetapi tetap saja, menandai metode virtual akan menyelesaikan masalah.
Tomas Aschan
+1 Tomas, saya perlu menyuntikkan parameter ke ctor, maka dalam kasus saya, saya harus mengejek kelas yang sebenarnya dan mengatur metode ke virtual, karena Anda tidak dapat memasukkan parameter ke dalam ctor Antarmuka. Apakah ini pendekatan yang tepat?
Houman
4
@Kave: Jika Anda perlu memasukkan sesuatu ke dalam konstruktor, Anda pasti menguji hal yang salah. Tiru apa pun yang Anda berikan kepada konstruktor, siapkan perilakunya dan uji apakah kelas ini berperilaku sebagaimana mestinya. Jika perlu, tulis antarmuka baru yang Anda jadikan implementasi jenis "injeksi" untuk mengakses semua tanda tangan metode.
Tomas Aschan