web-dev-qa-db-ja.com

非仮想メソッドをモックする方法は?

[TestMethod]
public void TestMethod1()
{
    var mock = new Mock<EmailService>();
    mock.Setup(x => x.SendEmail()).Returns(true);
    var cus = new Customer();
    var result = cus.AddCustomer(mock.Object);
    Assert.IsTrue(result);
}

public class Customer
{
    public bool AddCustomer(EmailService emailService)
    {
        emailService.SendEmail();
        Debug.WriteLine("new customer added");
        return true;
    }
}

public class EmailService
{            
    public virtual bool SendEmail()
    {
        throw  new Exception("send email failed cuz bla bla bla");
    }
}

EmailService.SendEmailメソッドは、モックするために仮想でなければなりません。非仮想メソッドをモックする方法はありますか?

32
hbmaam

Moqはクラスの非仮想メソッドをモックできません。実際にILをアセンブリに織り込む Type mock Isolator などの他のモックフレームワークを使用するか、EmailServiceにインターフェイスを配置してモックします。

22
aqwert

非仮想メソッドのモックには、低レベルのプロファイラーAPIの使用が含まれます。現時点では、利用できるオプションは次のとおりです。

どちらも商用版です。たとえJustMockにライトエディションが含まれていても、商用版でモッキング以外の仮想メソッドを使用できます。コメントで指摘したように、プロジェクトにはマイクロソフトの調査によるものがあります Pex and Moles

8
Felice Pollano

モックに仮想メソッドを使用する代わりに、インターフェイスを使用します。これにより、依存関係全体をモックアウトできます。

public interface IEmailService
{
    bool SendEmail();
    // etc...
}

public class EmailService : IEmailService
{
    //...
}

インターフェイスIEmailServiceのモックを作成して、そのメソッドをモックできるようになりました。もちろん、必要に応じて、EmailServiceオブジェクトを含む変数のタイプをIEmailServiceに変更する必要があります。

6
Alexander R

poseを使用します。静的または非仮想を含む任意のメソッドを置き換えることができます。かなり新しいプロジェクトですが、完全にオープンソースMITライセンス。 https://github.com/tonerdo/pose

4
James Reategui

Typemock Isolator を使用するときに@aqwertと@Feliceが書いたように、コードを追加または変更せずに非仮想メソッドをモックすることが可能です(非常に簡単です)。

[TestMethod,Isolated]
    public void TestMethod1()
    {
        var mock = Isolate.Fake.Instance<EmailService>();
        Isolate.WhenCalled(() => mock.SendEmail()).WillReturn(true);
        var cust = new Customer();
        var result = cust.AddCustomer(mock);
        Assert.IsTrue(result);
    }

作成したテストは、作成しようとしたテストに似ています。

2
Sam

非仮想メソッドをモックする唯一の方法は、そのクラスを非仮想メソッドで実装するために使用されるインターフェースをモックすることです。以下に例を示します。

public interface IEmployee
{
    DateTime GetDateofJoining(int id);
}

public class Employee
{
    public DateTime GetDateofJoining(int id)
    {
        return DateTime.Now;
    }
}

    public class Program
{
    static void Main(string[] args)
    {
        var employee = new Mock<IEmployee>();
        employee.Setup(x => x.GetDateofJoining(It.IsAny<int>())).Returns((int x) => DateTime.Now);

        Console.WriteLine(employee.Object.GetDateofJoining(1));
        Console.ReadLine();
    }
}
0
Rakesh Raut