无法形成最小起订量测试来欺骗上下文访问



一般的最小起订量和模拟测试是全新的。我正在尝试遵循教程,但适合我的需求,即通过实体框架核心上下文欺骗一些数据库访问。如何设置和测试返回 0 或任意数字的数据库的响应?

为了澄清,我想测试向我的 DoSomething 方法提供"Whatever"将返回 0,并且提供任何其他字符串将生成条目 Id。当然,Id 依赖于现实生活中的数据库增量,所以我只需要设置一个任意数字作为响应并测试是否返回它。当然,这是我真实方法的一个非常缩小的例子。

我已经尽可能地减少了设置:

接口:

public interface ITestClass
{
int DoSomething(string thing);
}

实现:

public class TestClass : ITestClass
{
private readonly TestContext _testContext;
public TestClass(TestContext testContext)
{
_testContext = testContext;
}
public int DoSomething(string thing)
{
if (thing == "Whatever") return 0;
Item i = new Item()
{
Thing = thing
};
_testContext.Add(i);
_testContext.SaveChanges();
return i.Id;
}
}

上下文:

public class TestContext : DbContext
{
public TestContext(DbContextOptions<TestContext> options) : base(options) { }
}

表/型号:

public class Item
{
public int Id { get; set; }
public string Thing { get; set; }
}

我忽略了连接字符串,因为重点是在不连接到数据库的情况下测试方法,对吗?最后,这是我嘲笑的尝试,我对此一无所知,tbh:

public void Test1()
{
var mock = new Mock<ITestClass>();
mock.Setup(m => m.DoSomething("Whatever"));
// Assert returns 0
mock.Setup(m => m.DoSomething("ValidString"));
// Assert returns arbitrary 12345 - where do I spoof this number?
}

我认为你对如何使用嘲笑有一个根本性的误解。让我们看看你的测试

public void Test1()
{
var mock = new Mock<ITestClass>();
mock.Setup(m => m.DoSomething("Whatever"));
// Assert returns 0
mock.Setup(m => m.DoSomething("ValidString"));
// Assert returns arbitrary 12345 - where do I spoof this number?
}

现在,当您在模拟上使用安装程序时,您还将使用 Returns、ReturnsAsync 或 Throws 来告诉模拟您希望它在提供这些值时返回什么。所以你的 DoSomething 设置应该看起来像这样

mock.Setup(m => m.DoSomething(It.Is<string>(i => i == "ValidString"))).Returns(12345);

但这里应该有一个明显的问题。如果我们明确地告诉它给定输入应该给我们什么,那么我们真正在测试什么?只是那时的模拟本身。这不是模拟的使用方式。所以有一条规则,永远不要嘲笑你正在测试的东西。相反,你嘲笑它的依赖关系。在这种情况下,唯一的一个是测试上下文。相反,我们实际上想要测试 DoSomething 方法,因此我们创建了该类的真实实例来测试。

您没有指定正在使用哪个测试框架,所以我用 NUnit 编写了我的

[Test]
public void Test1()
{
// Mock the dependency
Mock<ITestContext> mockContext = new Mock<ITestContext>();
mockContext.Setup(m => m.Add(It.IsAny<Item>()))
.Returns(true);
mockContext.Setup(m => m.SaveChanges())
.Returns(true);
// Inject the dependency
TestClass testClass = new TestClass(mockContext.Object);
int result = testClass.DoSomething("Whatever");
// Verify the methods on the mock were called once
mockContext.Verify(m => m.Add(It.IsAny<Item>()), Times.Once);
mockContext.Verify(m => m.SaveChanges(), Times.Once);
// Assert that the result of the operation is the expected result defined elsewhere
Assert.That(result, Is.EqualTo(ExpectedResult));
}

测试模拟是否返回您设置返回的内容没有任何价值。我们想测试真正的交易,当依赖关系很复杂时,模拟只是使这成为可能。它们是后端系统和真实系统在实践中使用的复杂对象图的替身,仅此而已。神奇之处在于,它允许我们只设置我们需要的模拟部分,依赖于它的类所依赖的特定函数调用和属性访问,而不必担心设置整个类及其所有依赖项等等。

相关内容

  • 没有找到相关文章