检查模拟中的更新实例

发布于 2024-08-22 16:22:10 字数 1724 浏览 6 评论 0原文

我有一个方法调用服务来检索对象的实例,更新实例,然后将实例保存回服务(其代码如下)。

我想知道的是,Moq 中是否有一种很好的方法来检查以下内容: -

  1. 保存回服务的实例是原始实例的修改版本
  2. 该实例已根据需要进行更新

我知道我可以使用 It.Is(x => x.Name == newName) 来检查此处的第 2 点。但这样做会忽略第 1 点。

有没有一种干净的方法来实现这一目标?

类别代码:

public class MyClass
{
    private readonly IThingService thingService;

    public MyClass(IThingService thingService)
    {
        this.thingService = thingService;
    }

    public void SaveMyThing(MyThing myThing)
    {
        var existingThing = thingService.Get(myThing.Id);
        existingThing.Name = myThing.Name;
        thingService.Save(existingThing);
    }
}

public class MyThing
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public interface IThingService
{
    MyThing Get(int id);
    void Save(MyThing myThing);
}

测试代码:

[Test]
public void Save_NewName_UpdatedThingIsSavedToService()
{
    // Arrange
    var myThing = new MyThing { 
                                Id = 42,
                                Name = "Thing1"
                            };
    var thingFromService = new MyThing
                    {
                        Id = 42,
                        Name = "Thing2"
                    };

    var thingService = new Mock<IThingService>();
    thingService
        .Setup(ts => ts.Get(myThing.Id))
        .Returns(thingFromService);
    thingService
        .Setup(ts => ts.Save(**UPDATED-THING-FROM-SERVICE**))
        .Verifiable();

    var myClass = new MyClass(thingService.Object);

    // Act
    myClass.SaveMyThing(myThing);

    // Assert
    thingService.Verify();
}

I have a method that calls a service to retrieve an instance of an object, updates the instance then saves the instance back to the service (the code for this is below).

What I want to know is if there is a nice way in Moq to check the following:-

  1. That the instance that is being saved back to the service is a modified version of the original instance
  2. That the instance has been updated as desired

I know I can use It.Is<MyThing>(x => x.Name == newName) to check for point 2 here. Doing this ignores point 1 though.

Is there a clean way to achieve this?

CLASS CODE:

public class MyClass
{
    private readonly IThingService thingService;

    public MyClass(IThingService thingService)
    {
        this.thingService = thingService;
    }

    public void SaveMyThing(MyThing myThing)
    {
        var existingThing = thingService.Get(myThing.Id);
        existingThing.Name = myThing.Name;
        thingService.Save(existingThing);
    }
}

public class MyThing
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public interface IThingService
{
    MyThing Get(int id);
    void Save(MyThing myThing);
}

TEST CODE:

[Test]
public void Save_NewName_UpdatedThingIsSavedToService()
{
    // Arrange
    var myThing = new MyThing { 
                                Id = 42,
                                Name = "Thing1"
                            };
    var thingFromService = new MyThing
                    {
                        Id = 42,
                        Name = "Thing2"
                    };

    var thingService = new Mock<IThingService>();
    thingService
        .Setup(ts => ts.Get(myThing.Id))
        .Returns(thingFromService);
    thingService
        .Setup(ts => ts.Save(**UPDATED-THING-FROM-SERVICE**))
        .Verifiable();

    var myClass = new MyClass(thingService.Object);

    // Act
    myClass.SaveMyThing(myThing);

    // Assert
    thingService.Verify();
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

枫以 2024-08-29 16:22:10

如果我理解正确的话,您想要验证传递给 ts.Save 的参数是否是从服务返回的实例。

如果是这样,除了验证 Name 值是否满足您的期望之外,还请检查引用相等性:

thingService
     .Setup(ts => ts.Save(It.Is<MyThing>(thing => thing == thingFromService
                                               && thing.Name = myThing.Name))
     .Verifiable();

If I understand correctly, you want to verify that the parameter passed to ts.Save is the instance returned from the service.

If that's true, check reference equality in addition to verifying that the Name value meets your expectations:

thingService
     .Setup(ts => ts.Save(It.Is<MyThing>(thing => thing == thingFromService
                                               && thing.Name = myThing.Name))
     .Verifiable();
天邊彩虹 2024-08-29 16:22:10

您已经差不多完成了:

[Test]
public void Save_NewName_UpdatedThingIsSavedToService()
{
    // Arrange
    var myThing = new MyThing { 
                                Id = 42,
                                Name = "Thing1"
                            };
    var thingFromService = new MyThing
                    {
                        Id = 42,
                        Name = "Thing2"
                    };

    var thingService = new Mock<IThingService>();
    thingService
        .Setup(ts => ts.Get(myThing.Id))
        .Returns(thingFromService)
        .Verifiable();
    thingService
        .Setup(ts => ts.Save(It.Is<MyThing>(x => x.Name == myThing.Name)))
        .Verifiable();

    var myClass = new MyClass(thingService.Object);

    // Act
    myClass.SaveMyThing(myThing);

    // Assert
    thingService.Verify();
}

主要区别是我还在第一个安装程序中添加了对 Verabilible() 的调用,然后添加了您已经提到过的 It.Is 检查在你的回答中。由于存在谓词,只有当谓词计算结果为 true 时,Save 方法才会匹配,在这种情况下,Verify 调用会成功。

然而,这个测试实际上测试了两件事(获取和保存)。为了避免断言轮盘,最好将其分成两个测试。

You are almost there:

[Test]
public void Save_NewName_UpdatedThingIsSavedToService()
{
    // Arrange
    var myThing = new MyThing { 
                                Id = 42,
                                Name = "Thing1"
                            };
    var thingFromService = new MyThing
                    {
                        Id = 42,
                        Name = "Thing2"
                    };

    var thingService = new Mock<IThingService>();
    thingService
        .Setup(ts => ts.Get(myThing.Id))
        .Returns(thingFromService)
        .Verifiable();
    thingService
        .Setup(ts => ts.Save(It.Is<MyThing>(x => x.Name == myThing.Name)))
        .Verifiable();

    var myClass = new MyClass(thingService.Object);

    // Act
    myClass.SaveMyThing(myThing);

    // Assert
    thingService.Verify();
}

The main difference is that I also added a call to Verifiable() to the first Setup, and then I added the It.Is check you already mentioned in your answer. Because of the predicate, the Save method will only be matched when the predicate evaluates to true, in which case the Verify call succeeds.

However, this test actually tests two things (Get and Save). To avoid Assertion Roulette, it would be better to split it up into two tests.

眼眸里的那抹悲凉 2024-08-29 16:22:10

我同意马克的回答,但对你的第一个陈述有点困惑。您是否想查明该对象是否是相同的对象引用或对象类型? It.Is 只是确保参数是 MyThing 的类型,而不是确保它是对先前对象的实际引用。

如果您想拦截传递给模拟服务的值,则可以使用如下所示的回调,然后对结果对象执行您想要的任何断言:

MyThing result = null;

thingService
    .Setup(ts => ts.Save(It.Is<MyThing>(x => x.Name == myThing.Name)))
    .Callback((MyThing saved) => result = saved)
    .Verifiable();

I agree with Mark's answer but a bit confused by your first statement. Are you trying to find out if the object is the same object reference or object type? The It.Is just makes sure that parameter is the type of MyThing, not that it is the actual reference to your previous object.

If you want to intercept the value being passed to your mock service than you could use a callback like below and then do whatever assertions you want on the result object:

MyThing result = null;

thingService
    .Setup(ts => ts.Save(It.Is<MyThing>(x => x.Name == myThing.Name)))
    .Callback((MyThing saved) => result = saved)
    .Verifiable();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文