当前位置: 首页 > 知识库问答 >
问题:

使用Moq更新,删除单元测试的方法

姬振濂
2023-03-14

我在单元测试中使用了Moq框架。这是UpdateApplication测试方法:

[TestMethod]
public void UpdateApplication()
{
    const string newAplpicationName = "NewApplication1";

    var data =
        new[]
        {
            new Application { Id = 1, Name = "Application1" }, new Application { Id = 2, Name = "Application2" },
            new Application { Id = 3, Name = "Application3" }, new Application { Id = 4, Name = "Application4" }
        }
            .AsQueryable();

    var mockSet = new Mock<DbSet<Application>>();
    mockSet.As<IQueryable<Application>>().Setup(m => m.Provider).Returns(data.Provider);
    mockSet.As<IQueryable<Application>>().Setup(m => m.Expression).Returns(data.Expression);
    mockSet.As<IQueryable<Application>>().Setup(m => m.ElementType).Returns(data.ElementType);
    mockSet.As<IQueryable<Application>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());

    mockSet.Setup(m => m.AddOrUpdate(It.IsAny<Application[]>())).Callback(
        (Application[] apps) =>
        {
            apps.FirstOrDefault(m => m.Id == 1).Name = newAplpicationName;
        }).Verifiable(); // <-- Exception

    var mockContext = new Mock<AppDbContext>();
    mockContext.Setup(c => c.Applications).Returns(mockSet.Object);

    // Act 
    var commandHandler = new UpdateApplicationCommandHandler(mockContext.Object);
    var commandArg = new ApplicationCommandArg { Id = 1, Name = newAplpicationName };
    commandHandler.Execute(new UpdateApplicationCommand(commandArg));

    // Verify
    mockContext.Verify(m => m.SaveChanges(), Times.Once());
}

我在运行测试时遇到一个异常:

An exception of type 'System.NotSupportedException' occurred in Moq.dll but was
not handled in user code

Additional information: Expression references a method that does not belong to
the mocked object: m => m.AddOrUpdate(It.IsAny())

   at Moq.Mock.ThrowIfNotMember(Expression setup, MethodInfo method)
   at Moq.Mock.c__DisplayClass19`1.b__18()
   at Moq.PexProtector.Invoke[T](Func`1 function)
   at Moq.Mock.Setup[T](Mock`1 mock, Expression`1 expression, Condition condition)
   at Moq.Mock`1.Setup(Expression`1 expression)
   at UpdateApplication() in UpdateApplicationCommandTests.cs:line 39

我应该如何编写使用Moq更新和删除操作的单元测试?

共有2个答案

韩善
2023-03-14

问题是addOrUpdate是一个扩展方法。Moq不能模拟扩展方法,因此您需要找到另一种方法来实现测试覆盖率。

澹台举
2023-03-14

UpdateApplication单元测试方法的这种变体适用于我,但我不确定它是否正确:

    [TestMethod]
    public void UpdateApplication()
    {
        const string newAplpicationName = "NewApplication1";

        var data =
            new[]
            {
                new Application { Id = 1, Name = "Application1" }, new Application { Id = 2, Name = "Application2" },
                new Application { Id = 3, Name = "Application3" }, new Application { Id = 4, Name = "Application4" }
            }
                .AsQueryable();

        var mockSet = new Mock<DbSet<Application>>();
        mockSet.As<IQueryable<Application>>().Setup(m => m.Provider).Returns(data.Provider);
        mockSet.As<IQueryable<Application>>().Setup(m => m.Expression).Returns(data.Expression);
        mockSet.As<IQueryable<Application>>().Setup(m => m.ElementType).Returns(data.ElementType);
        mockSet.As<IQueryable<Application>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());

        var mockContext = new Mock<AppDbContext>();
        mockContext.Setup(m => m.Applications).Returns(mockSet.Object);


        // Act 
        var commandHandler = new UpdateApplicationCommandHandler(mockContext.Object);
        var commandArg = new ApplicationCommandArg { Id = 1, Name = newAplpicationName };
        commandHandler.Execute(new UpdateApplicationCommand(commandArg));

        Assert.AreEqual(newAplpicationName, data.First(m => m.Id == 1).Name);

        mockContext.Verify(m => m.SaveChanges(), Times.Once());
    }

但是我的DeleteApplicationCommand和Test仍然存在问题。当我运行测试时,我得到一个excepton“预期在模拟上调用了整整3次,但是是2次:m=

    [TestMethod]
    public void DeleteApplication()
    {
        var data =
            new[]
            {
                new Application { Id = 1, Name = "Application1" }, new Application { Id = 2, Name = "Application2" },
                new Application { Id = 3, Name = "Application3" }, new Application { Id = 4, Name = "Application4" }
            }
                .AsQueryable();

        var mockSet = new Mock<DbSet<Application>>();
        mockSet.As<IQueryable<Application>>().Setup(m => m.Provider).Returns(data.Provider);
        mockSet.As<IQueryable<Application>>().Setup(m => m.Expression).Returns(data.Expression);
        mockSet.As<IQueryable<Application>>().Setup(m => m.ElementType).Returns(data.ElementType);
        mockSet.As<IQueryable<Application>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());

        var mockContext = new Mock<AppDbContext>();
        mockContext.Setup(m => m.Applications).Returns(mockSet.Object);

        // Act 
        var commandHandler = new DeleteApplicationCommandHandler(mockContext.Object);
        var commandArg = new ApplicationCommandArg { Id = 1 };
        commandHandler.Execute(new DeleteApplicationCommand(commandArg));

        // Verify
        mockSet.Verify(m => m.Remove(It.IsAny<Application>()), Times.Once());
        mockContext.Verify(m => m.SaveChanges(), Times.Once());
        mockContext.VerifyGet(m => m.Applications, Times.Exactly(3));
    }

这是我的执行DeleteApplication ation命令dHandler的方法:

    public override void Execute(DeleteApplicationCommand command)
    {
        Debug.WriteLine("DeleteApplicationCommand executed");

        var application = this.DbContext.Applications.FirstOrDefault(m => m.Id == command.CommandArg.Id);

        if (application == null)
        {
            throw new Exception(string.Format("Application with id {0} was not found", command.CommandArg.Id));
        }

        this.DbContext.Applications.Remove(application);

        this.DbContext.SaveChanges();
    }

为什么应用程序测试方法失败?

 类似资料:
  • 我有一个,它有几个不同的查询来更新表。这些方法没有使用注释,因为事务是在服务级别上进行的。 我想测试这些存储库。我创建了一个用注释的测试类,但是当调用存储库方法时,它们会失败: 如果我用注释每个存储库方法,它会修复错误,但我不想更改主代码库。我应该能够在测试中创建事务。 我已经创建了一些示例代码来展示我所拥有的一般结构。 存储库 测验 例外 将测试注释为“@Transactional”不应该解决这

  • 如果我错了请纠正我,但看起来Moq只能模拟一个公共类,它有一个公共的无参数构造函数,要模拟的方法是。我并不想让这些类公开可见。我是不是错过了一些与Moq的东西,或者只是不适合我想做的事情? 我想我可以创建一个ClassB实现的接口(例如“ICLASSB”),将其注入ClassA,并模拟该接口。ClassB仍然可以是内部的(尽管我意识到接口方法必须是公共的)。虽然这可以工作,但我对创建大量接口感到不

  • 请容忍我,因为这是我第一次使用Spring靴,所以这只是我认为正在发生的事情。。。 我有两个方法,都是用Scheduled注释的。它们工作得很好,我已经配置并注入了所有依赖项。这些依赖关系非常重,依赖于internet连接等。我将它们注释为懒惰,因此它们只是在最后一刻才实例化。 但是,包含计划方法的类需要标记为组件,这意味着它们是在启动时创建的。这引发了一个连锁反应,它会创建我的所有依赖项,无论我

  • 我正在尝试使用Moq创建一组测试方法来覆盖外部依赖项。这些依赖关系本质上是异步的,我遇到过一组当等待它们时,它们永远不会返回,所以我不确定我遗漏了什么。 测试本身非常简单。 上面的方法是设置各种模拟对象的方法,包括对它们调用的Setup。 下面列出了测试中的代码,当执行带有等待的行时,它永远不会返回。 我确定错误在方法中Moq对象的方法中,但我不确定问题出在哪里。

  • 我使用Hive1.2.1和TEZ0.7进行测试,但是当我使用acid表进行更新和删除时,出现了一些问题,下面是表的结构:

  • 我正在将Grails2中的一系列单元测试升级到Grails3,并且在使用GORM动态方法的域测试中遇到了问题--特别是addTo{myHasMany}方法。 给定以下域对象 > 我尝试使用DomainClassUnitTestMixin和mockDomain()方法模拟Contact实例,以生成带有GORM方法(或子集)的实例。 我已经尝试了使用基于Spock交互的测试支持的方法。 事实上,我已经