Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/280.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.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# Moq verify使用在返回中修改的对象,而不是实际传入的对象_C#_Unit Testing_Moq - Fatal编程技术网

C# Moq verify使用在返回中修改的对象,而不是实际传入的对象

C# Moq verify使用在返回中修改的对象,而不是实际传入的对象,c#,unit-testing,moq,C#,Unit Testing,Moq,背景 我有一个类,它使用NHibernate将对象持久化到数据库。当为未设置ID的对象调用MergeEntity时,NHibernate会在返回该对象时使用ID填充该对象。为了确保我始终使用与NHibernate使用的对象相同的对象,我将更新后的对象从我的“Save”函数传回 问题 我试图用Moq来模拟同样的行为,Moq通常是非常直观和易于使用的;但是,我在验证对Save()的调用是否使用正确的参数时遇到了一些问题。我想验证传入的对象的ID是否为零,然后验证它是否由Save函数正确设置。不幸的是

背景

我有一个类,它使用NHibernate将对象持久化到数据库。当为未设置ID的对象调用
MergeEntity
时,NHibernate会在返回该对象时使用ID填充该对象。为了确保我始终使用与NHibernate使用的对象相同的对象,我将更新后的对象从我的“
Save
”函数传回

问题

我试图用Moq来模拟同样的行为,Moq通常是非常直观和易于使用的;但是,我在验证对
Save()
的调用是否使用正确的参数时遇到了一些问题。我想验证传入的对象的ID是否为零,然后验证它是否由
Save
函数正确设置。不幸的是,当我在
Moq.Returns()
函数中修改ID时,
Moq.Verify
函数使用修改后的值,而不是传入的ID值

为了举例说明,这里有一个非常基本的类(我重写了ToString()函数,因此我的测试输出将显示调用模拟Save()时使用的ID):

以下是我认为应该通过的测试:

[TestFixture]
public class Class1Tests
{
    [Test]
    public void Save_NewObjects_IdsUpdated()
    {
        var mock = new Mock<IPersistence>();
        mock.Setup(x => x.Save(It.IsAny<Class1>()))
            .Returns((Class1 c) =>
            {
                // If it is a new object, then update the ID
                if (c.Id == 0) c.Id = 1;

                return c;
            });

        // Verify that the IDs are updated for new objects when saved
        var one = new Class1(mock.Object);

        Assert.AreEqual(0, one.Id);

        one.Save();

        mock.Verify(x => x.Save(It.Is<Class1>(o => o.Id == 0)));
    }
}
[TestFixture]
公开班级考试
{
[测试]
public void Save_NewObjects_IdsUpdated()
{
var mock=new mock();
mock.Setup(x=>x.Save(It.IsAny()))
.返回((c类)=>
{
//如果是新对象,则更新ID
如果(c.Id==0)c.Id=1;
返回c;
});
//确认保存时已更新新对象的ID
var one=新类别1(mock.Object);
arest.AreEqual(0,一个.Id);
一、保存();
mock.Verify(x=>x.Save(It.Is(o=>o.Id==0));
}
}

不幸的是,它没有说明从未使用符合该条件的参数调用它。在模拟中对
Save
的唯一调用是使用ID为1的对象。我已经验证了当对象进入Returns函数时,它们的ID为0。如果我更新我的
Returns()
函数中的值,我是否无法区分传入模拟的内容和更新的对象是什么?

您可以将其切换,以验证是否使用正确的对象进行了保存。然后断言Id已按预期更改

[Test]
public void Save_NewObjects_IdsUpdated() {
    //Arrange
    var expectedOriginalId = 0;
    var expectedUpdatedId = 1;
    var mock = new Mock<IPersistence>();
    mock.Setup(x => x.Save(It.Is<Class1>(o => o.Id == expectedOriginalId)))
        .Returns((Class1 c) => {
            // If it is a new object, then update the ID
            if (c.Id == 0) c.Id = expectedUpdatedId;

            return c;
        }).Verifiable();

    var sut = new Class1(mock.Object);
    var actualOriginalId = sut.Id;

    //Act
    sut.Save();

    //Assert

    //verify id was 0 before calling method under test
    Assert.AreEqual(expectedOriginalId, actualOriginalId);
    //verify Save called with correct argument
    //ie: an object that matched the predicate in setup
    mock.Verify();
    // Verify that the IDs are updated for new objects when saved
    Assert.AreEqual(expectedUpdatedId, sut.Id);
}
[测试]
public void Save_NewObjects_IdsUpdated(){
//安排
var expectedOriginalId=0;
var expectedUpdatedId=1;
var mock=new mock();
mock.Setup(x=>x.Save(It.Is(o=>o.Id==expectedOriginalId)))
.返回((c类)=>{
//如果是新对象,则更新ID
如果(c.Id==0)c.Id=expectedUpdatedId;
返回c;
}).可验证();
var sut=new Class1(mock.Object);
var Actual LoriginAlid=sut.Id;
//表演
sut.Save();
//断言
//在调用测试中的方法之前验证id为0
Assert.AreEqual(expectedOriginalId,ActualIginAlid);
//验证是否使用正确的参数调用了Save
//ie:与设置中的谓词匹配的对象
mock.Verify();
//确认保存时已更新新对象的ID
AreEqual(expectedUpdatedId,sut.Id);
}
通过在安装程序上应用过滤器并使其可验证,然后确认该方法实际上是使用ID为零的对象调用的

我已经测试过了,它通过了。要确认is按预期工作,您可以在执行act之前将sut的id从预期的开始id更改为。验证将失败,因为它与谓词不匹配


这应该满足您想要达到的目标。

只测试前后状态,这可以通过许多不同的方法实现。它不会测试是否将正确的对象传递到Save函数中。事实上,我还有其他测试,这些测试与您在这里所做的完全相同,但我有一个错误,我一直在创建新对象,而不是使用现有对象,因此我需要一种方法来确保我在中传递了正确的对象。
mock.Verify(x=>x.Save(sut))检查是否传递了正确的对象。您使用is any设置它,然后确认正确的对象(在本例中为
Class1 sut
)已传递到itSort of…中,但在验证时,“sut”具有更新的ID。我想测试传递的对象的ID是否为零。此测试无法验证。@MattZappitello然后您需要更改设置和验证方式。检查更新的答案。如果您认为GitHub应该支持您尝试的操作,您可以在GitHub上记录问题。也许开发人员可以更好地了解这个问题。
[TestFixture]
public class Class1Tests
{
    [Test]
    public void Save_NewObjects_IdsUpdated()
    {
        var mock = new Mock<IPersistence>();
        mock.Setup(x => x.Save(It.IsAny<Class1>()))
            .Returns((Class1 c) =>
            {
                // If it is a new object, then update the ID
                if (c.Id == 0) c.Id = 1;

                return c;
            });

        // Verify that the IDs are updated for new objects when saved
        var one = new Class1(mock.Object);

        Assert.AreEqual(0, one.Id);

        one.Save();

        mock.Verify(x => x.Save(It.Is<Class1>(o => o.Id == 0)));
    }
}
[Test]
public void Save_NewObjects_IdsUpdated() {
    //Arrange
    var expectedOriginalId = 0;
    var expectedUpdatedId = 1;
    var mock = new Mock<IPersistence>();
    mock.Setup(x => x.Save(It.Is<Class1>(o => o.Id == expectedOriginalId)))
        .Returns((Class1 c) => {
            // If it is a new object, then update the ID
            if (c.Id == 0) c.Id = expectedUpdatedId;

            return c;
        }).Verifiable();

    var sut = new Class1(mock.Object);
    var actualOriginalId = sut.Id;

    //Act
    sut.Save();

    //Assert

    //verify id was 0 before calling method under test
    Assert.AreEqual(expectedOriginalId, actualOriginalId);
    //verify Save called with correct argument
    //ie: an object that matched the predicate in setup
    mock.Verify();
    // Verify that the IDs are updated for new objects when saved
    Assert.AreEqual(expectedUpdatedId, sut.Id);
}