Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sql-server-2005/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Xunit中的模拟-如何验证返回某些值的方法_C#_.net Core_Moq_Xunit - Fatal编程技术网

C# Xunit中的模拟-如何验证返回某些值的方法

C# Xunit中的模拟-如何验证返回某些值的方法,c#,.net-core,moq,xunit,C#,.net Core,Moq,Xunit,我已经创建了一个单元测试方法来验证方法是否被调用,下面是相同的代码 public class SMTPEmailSender : IEmailSender { private IPDFCreater _pdfCreater; public SMTPEmailSender(IPDFCreater pdfCreater) { _pdfCreater = pdfCreater; } public Email BuildEmailInfo(str

我已经创建了一个单元测试方法来验证方法是否被调用,下面是相同的代码

public class SMTPEmailSender : IEmailSender
{
    private IPDFCreater _pdfCreater;

    public SMTPEmailSender(IPDFCreater pdfCreater)
    {
        _pdfCreater = pdfCreater;
    }
    public Email BuildEmailInfo(string sMTPServerUrl, FaxMailDTO faxAsMailRequest)
    {
        Email email=null;
        try
        {
            var otp = new PDFData { OTP =faxAsMailRequest.OTP};
            email = new Email
            {
                SMTPServerUrl = sMTPServerUrl,
                Encoding = Encoding.UTF8,

                ToAddress = faxAsMailRequest.ToEmailAddress,
                ToAddressDisplayName = faxAsMailRequest.ToAddressDisplayName,
                FromAddress = faxAsMailRequest.FromEmailAddress,
                Subject = faxAsMailRequest.Subject,
                Body = faxAsMailRequest.Body,
                FromAddressDisplayName = faxAsMailRequest.FromAddressDisplayName,
                ContentStream = new MemoryStream(_pdfCreater.GeneratePDF(otp)),
                AttachmentName = faxAsMailRequest.FaxFileName
                
            };
        }
        catch(Exception ex)
        {
            Log.Error("Method : BuildEmailInfo. Exception raised while building email data : {@Message}", ex.Message, ex);
        }
        

       

        return email;
    }
下面是我的单元测试代码,每当我执行它时,它至少会在模拟上抛出一次错误预期调用,但从未执行过:x=>x.GeneratePDF(pdfdata)。另外,请让我知道这是否是执行测试的正确方法

public class SMTPEmailSenderTest
{
    private SMTPEmailSender _sMTPEmailSender;
    Mock<IPDFCreater> _mockPdfCreator;
    public SMTPEmailSenderTest()
    {
        _mockPdfCreator = new Mock<IPDFCreater>();
        _sMTPEmailSender = new SMTPEmailSender(_mockPdfCreator.Object);
    }


    [Theory]
    [MemberData(nameof(GetFaxAsMailObject))]
    public void BuildEmailInfoTest_ReturnsValidEmailObject(FaxMailDTO faxMailDTO)
    {
        string smpturl = "localhost";
        var otp = new PDFData { OTP = faxMailDTO.OTP };
        var result = _sMTPEmailSender.BuildEmailInfo(smpturl, faxMailDTO);
        _mockPdfCreator.Verify(x => x.GeneratePDF(otp));
    }
  }
公共类SMTPEmailSenderTest
{
私有SMTPEmailSender\u SMTPEmailSender;
Mock_mockPdfCreator;
公共SMTPEmailSenderTest()
{
_mockPdfCreator=新建Mock();
_sMTPEmailSender=新的sMTPEmailSender(\u mockPdfCreator.Object);
}
[理论]
[成员数据(名称(GetFaxAsMailObject))]
public void BuildEmailInfoTest_返回验证邮件对象(FaxMailDTO FaxMailDTO)
{
字符串smpturl=“localhost”;
var otp=newpdfdata{otp=faxMailDTO.otp};
var result=_sMTPEmailSender.BuildEmailInfo(smptur,faxMailDTO);
_mockPdfCreator.Verify(x=>x.GeneratePDF(otp));
}
}

在单元测试中,对模拟对象的验证应该是您的“最后手段”。想想看:如果PDF创建者不调用GeneratePDF方法,是否违反了实际需求?用户只关心PDF是否已生成

在这种情况下,您可以直接验证BuildEmailInfo方法的结果,例如:

var result =  _sMTPEmailSender.BuildEmailInfo(smpturl, faxMailDTO);
var expectedBytes = ...; // TODO - get the expected byte[] array from somewhere
Assert.Equal(expectedBytes, result.ContentStream.ToArray());
        _myMock.Verify(x => x.FooBar(5));
        _myMock.Verify(x => x.FooBar(123));
        _myMock.Verify(x => x.FooBar(It.IsAny<int>());
        _myMock.Verify(x => x.FooBar(It.Is<int>(number => (number-5)%3 > 10));
此外,您可以编写此测试,而无需模拟依赖关系?如果可以调用实际的PDF creator对象在内存中生成byte[]数组,则可以使用实际对象而不是模拟它。

此行:

        _mockPdfCreator.Verify(x => x.GeneratePDF(otp));
执行“验证”。这是一个断言,用于检查是否已在
\u mockPdfCreator
上调用了方法
.GeneratePDF
,并将
otp
作为其参数

来自模拟对象接口的All.Verify方法用于检查是否调用了某些方法或属性。您还可以提供一些过滤器来查看是否传递了某些参数,例如:

var result =  _sMTPEmailSender.BuildEmailInfo(smpturl, faxMailDTO);
var expectedBytes = ...; // TODO - get the expected byte[] array from somewhere
Assert.Equal(expectedBytes, result.ContentStream.ToArray());
        _myMock.Verify(x => x.FooBar(5));
        _myMock.Verify(x => x.FooBar(123));
        _myMock.Verify(x => x.FooBar(It.IsAny<int>());
        _myMock.Verify(x => x.FooBar(It.Is<int>(number => (number-5)%3 > 10));
\u mockPdfCreator
是您的模拟对象。不是真的。这是一个小小的幽灵,就像是某个IPDFreater

那里没有一点真正的实现。
您怎么能期望
GeneratePDF
返回任何有意义的内容?
只是不会。后面什么都没有。如果有任何东西调用该方法
GeneratePDF
,它将返回NULL(或抛出异常,具体取决于模拟模式:松散/严格)

…除非您将模拟设置为不同的方式:

    var theThing = ...;
    _mockPdfCreator = new Mock<IPDFCreater>();
    _mockPdfCreator.Setup(x => x.GeneratePDF(It.IsAny<...>())).Returns(theThing);
    ....
    // ... now check what `GeneratePDF` returned?!
然后在测试中,您已经:

    _mockPdfCreator = new Mock<IPDFCreater>();
    ....
    _mockPdfCreator.Verify(x => x.GeneratePDF(otp));
    ....
    var result = _sMTPEmailSender.BuildEmailInfo(smpturl, faxMailDTO);
    _mockPdfCreator.Verify(x => x.GeneratePDF(otp));
显然,
\u sMTPEmailSender.BuildEmailInfo
根本不喜欢调用
GeneratePDF

为什么??不知道。很可能在
smpturl
faxMailDTO
中存在被认为对此用例无效且生成pdf步骤被跳过的内容。检查结果。查看是否有任何错误或消息可以告诉您为什么它甚至没有尝试调用GeneratePDF

还要注意,您编写的验证是

x => x.GeneratePDF(otp)
这很具体。它具有指向otp的硬编码引用。也许它被调用了,但参数值不同

尝试添加:

    var result = _sMTPEmailSender.BuildEmailInfo(smpturl, faxMailDTO);
    _mockPdfCreator.Verify(x => x.GeneratePDF(It.IsAny<PDFData>())); // <-
    _mockPdfCreator.Verify(x => x.GeneratePDF(otp));
因此,
faxMailDTO
来自GetFaxAsMailObject。BuildEmailInfo通过params获取它,并将其中的一部分传递给GeneratePDF。然后您在Verify中断言D使用了从第C行新构造的
otp
。这根本无法工作。来自A+B的
faxMailDTO
,因此来自
GetFaxAsMailObject
的肯定不包含来自C的
otp
,肯定不会将
otp
对象传递给GeneratePDF。GeneratePDF将从A+B获取来自
faxMailDTO
的其他PDFData对象


我想我已经说得够多了,涵盖了您的测试设置的所有问题。。你几乎说对了。祝你好运

我们如何使用real object,请您指导我如何做,我将需要新的SMTPEmailSender的real object,正如您所见,我将必须调用SMTPEmailSender(_mockPdfCreator.object),它接受模拟PDFCreateries,确切地说。我的建议是去掉模拟pdfcreator并注入实际对象(如果可能的话):new-SMTPEmailSender(new-pdfcreator())或类似的东西。
(…)去掉模拟pdfcreator并注入实际对象:new-SMTPEmailSender(new-pdfcreator())或者类似的东西。
-这是你能给Vishal的最糟糕的暗示之一。一切都准备好了单独测试。他可以使用IPDFCreater mock测试SMTP(..)BuildEmailInfo以查看BuildEmailInfo是否正常工作,并且可以在没有SMTPEmailSender的情况下测试IPDFCreater的实际实现。可以将这些测试混合在一起,但为什么呢?如果出现任何问题,就很难判断故障是在1级还是2级。Vishal只需要修复他的测试设置。@jeroenh您的解决方案确实有效,但做了一些更改,但我想这会给需要模拟的方法带来问题,谢谢。我可以将您的答案用于其他场景sadding _mockPdfCreator.Verify(x=>x.GeneratePDF(it.IsAny());使我的代码工作。谢谢您的解释应该是Moq文档的一部分!我知道格扎尔卡特已经找到了你的主要问题。但在我看来,除非进行模拟设置,否则BuildMailInfo中总是会抛出异常。否则,MemoryStream的构造函数将始终获得空参数。