考虑一个需要编写的场景
integration tests
对于
REST API
控制器。我用
MSTest
为了这个。逻辑如下:
-
创造新的
database
,运行init
SQL
迁徙
-
创建测试
HTTP Client
打电话反对
endpoints
-
DB
.
用例
大多数端点都进行验证,无论
SQL
命令(
INSERT
,
UPDATE
,
DELETE
)返回了一个成功结果(布尔值)
true
)或者不是。要复制这个场景,我需要知道
SQL
故障条件(硬),或者更简单的选择是
能够模拟存储库
.当然,这不再是一个完整的集成测试,但至少我能够进行测试
REST
这样的商业逻辑
HTTP response status codes
。另外一个好处是测试DB事务回滚功能。
问题
因此,我想知道——是否有可能创建一个模拟,默认情况下会返回实际对象实例的所有值,除非
setup()
是否提供了覆盖?
示例/工作代码
在测试初始化时,我们创建一个HTTP测试客户端实例和一个模拟存储库:
_usersRepo = new UsersRepository(); // actual instance of repository
var application = new WebApplicationFactory<Startup>()
.WithWebHostBuilder(builder =>
{
builder.ConfigureTestServices(services =>
{
_usersRepoMock = new Mock<IUsersRepository>();
// setting mock just for 1 of the methods manually
_usersRepoMock
.Setup(p => p.GetByIdAsync(It.IsAny<long>()))
.Returns(async (long r) => await _usersRepo.GetByIdAsync(r));
services.AddSingleton<IUsersRepository>(_usersRepoMock.Object);
});
});
_client = application.CreateClient(new WebApplicationFactoryClientOptions());
我已经手动配置了一个模拟来返回结果
从实际的存储库
对于单一方法。
然后,在测试课上,每当我需要一些不及格的东西时,我都会做以下事情:
[TestMethod]
public async Task Db_throws_exception()
{
_usersRepoMock.Setup(p => p.GetByIdAsync(It.IsAny<long>())).Throws(new System.Exception("test"));
//.. rest of the code
}
这个解决方案正如预期的那样工作,然而,问题是为了让这种方法工作,我需要手动将所有模拟对象请求代理到实际实例。我在每次回购中有大约4-6种方法,以及大约8种不同的回购(未来会有更多)
我想避免这样做
.可能吗?
以下是我想避免做的事情:
_usersRepoMock = new Mock<IUsersRepository>();
_usersRepoMock.Setup(p => p.GetByIdAsync(It.IsAny<long>())).Returns(async (long r) => await _usersRepo.GetByIdAsync(r));
_usersRepoMock.Setup(p => p.Create(It.IsAny<long>())).Returns(async (long r) => await _usersRepo.Create(r));
_usersRepoMock.Setup(p => p.Update(It.IsAny<long>())).Returns(async (long r) => await _usersRepo.Update(r));
_repo2Mock = new Mock<IRepo2>();
_repo2Mock.Setup(p => p.Method1(It.IsAny<long>())).Returns(async (long r) => await _repo2.Method1(r));
_repo2Mock.Setup(p => p.Method2(It.IsAny<long>())).Returns(async (long r) => await _repo2.Method2(r));
_repo2Mock.Setup(p => p.Method3(It.IsAny<long>())).Returns(async (long r) => await _repo2.Method3(r));
_repo2Mock.Setup(p => p.Method4(It.IsAny<long>())).Returns(async (long r) => await _repo2.Method4(r));
_repo2Mock.Setup(p => p.Method5(It.IsAny<long>())).Returns(async (long r) => await _repo2.Method5(r));
_repo3Mock = new Mock<IRepo3>();
_repo3Mock.Setup(p => p.Method1(It.IsAny<long>())).Returns(async (long r) => await _repo3.Method1(r));
_repo3Mock.Setup(p => p.Method2(It.IsAny<long>())).Returns(async (long r) => await _repo3.Method2(r));
_repo3Mock.Setup(p => p.Method3(It.IsAny<long>())).Returns(async (long r) => await _repo3.Method3(r));
_repo3Mock.Setup(p => p.Method4(It.IsAny<long>())).Returns(async (long r) => await _repo3.Method4(r));
_repo3Mock.Setup(p => p.Method5(It.IsAny<long>())).Returns(async (long r) => await _repo3.Method5(r));
关于stackoverflow有一些类似的问题,但我找不到与我相同的用例,也找不到一个可接受的问题答案。。以下是一个例子:
Default behavior for mock inherited from object instance
p、 我写这个问题的时间可能比写模拟代码的时间要多:)