C# 有没有一种方法可以将TestServer和moq Mock结合起来进行测试,以替换ConfigureTestServices中类中的方法?

C# 有没有一种方法可以将TestServer和moq Mock结合起来进行测试,以替换ConfigureTestServices中类中的方法?,c#,unit-testing,asp.net-core-mvc,integration-testing,moq,C#,Unit Testing,Asp.net Core Mvc,Integration Testing,Moq,我能够使用进行集成测试,并且我可以通过将ConfigureTestServices中的类替换为模拟类来手动模拟任何DI注入类中的方法,如下所示: var webHostBuilder = new WebHostBuilder() .UseEnvironment("Testing") .UseContentRoot(projectDir) .ConfigureTestServices(s => {

我能够使用进行集成测试,并且我可以通过将
ConfigureTestServices
中的类替换为模拟类来手动模拟任何DI注入类中的方法,如下所示:

var webHostBuilder =
    new WebHostBuilder()
        .UseEnvironment("Testing")
        .UseContentRoot(projectDir)
        .ConfigureTestServices(s =>
        {
            s.TryAddTransient(IMyClass, MyMockMyClass);
        })
        .UseStartup<Startup>();

然后以某种方式将此
mymock
与行
s.TryAddTransient一起使用(IMyClass,
在上面的
ConfigureTestServices
代码中?

可以使用mock构建服务集合并将其提供给测试服务器,但您不应该这样做。测试服务器用于进行集成测试,而mock用于单元测试。您需要确定正在进行的测试类型,并选择一种或多种测试另一个

顾名思义,单元测试涉及到测试一个离散的功能单元。模拟是一种删除变量的方法,这样你就可以确保你正在测试的一件事情是否有效

另一方面,集成测试是关于自上而下测试系统。您希望确保给定的输入产生给定的输出,使用系统中的所有内容。如果您加入模拟,那么您就不会测试任何内容,因为您现在不知道它是否工作,仅仅是因为模拟或实际系统损坏


例如,假设您有一个特定操作使用的服务,该服务有一个bug,将导致该操作实时抛出异常。但是,您可以在测试服务器中将其替换为一个mock,这很好。您的测试通过,因为mock正在工作,但当您实时推送它时,一切都会中断。相反,您可以fail正确模拟服务,即使实际服务正常,您的测试也可能失败。除非您使用真实系统进行测试,否则您对任何事情都没有把握。

请工厂代表在配置测试服务器时返回模拟服务

var mymock = Mock.Of<IMyClass>();
Mock.Get(mymock)
    .Setup(m => m.Method1(It.IsAny<string>())
    .Returns(value: whatever);

var webHostBuilder =
    new WebHostBuilder()
        .UseEnvironment("Testing")
        .UseContentRoot(projectDir)
        .ConfigureTestServices(services => {
            services.RemoveAll<IMyClass>();//Remove previous registration(s) of this service
            services.TryAddTransient<IMyClass>(sp => mymock);
        })
        .UseStartup<Startup>();
var mymock=Mock.Of();
Mock.Get(mymock)
.Setup(m=>m.Method1(It.IsAny())
.返回值(值:任意值);
var webHostBuilder=
新WebHostBuilder()
.UseEnvironment(“测试”)
.UseContentRoot(项目目录)
.ConfigureTestServices(服务=>{
services.RemoveAll();//删除此服务以前的注册
services.TryAddTransient(sp=>mymock);
})
.UseStartup();

如果每次调用都需要一个新的模拟实例,那么将逻辑移到工厂委托中

@chris_pratt,我明白了你的意思。实际上,需要moq,因为在集成测试中,我们需要使用to-in-memory DB而不是真正的SQL DB,而且其中一个底层方法正在使用与之不兼容的复杂查询内存中的数据库,因此使用moq来简化底层方法的想法。您有什么建议?如果SUT依赖于特定的数据库提供程序,那么您的集成测试应该直接使用此类提供程序,而不是内存中的数据库。其他不太依赖的集成测试可以继续使用内存中的提供程序ider。如果您模拟查询,那么测试无论如何都是毫无意义的,因此您甚至可以不浪费时间编写它。在这个特定的测试中,查询本身对结果并不重要。另外,在实际数据库上进行测试需要处理在每个测试结束时将数据库恢复到其以前的状态。1)如果查询对结果不重要,那么它首先就不应该是系统的一部分。不确定您到底在做什么,但是作为视图组件的一部分可能会更好,例如。在任何一种情况下,您都应该有某种回退或捕获,因为如果它真的不重要,那么无论什么原因都会失败原因不应该让你的系统崩溃。2)如果你正确使用测试服务器,你应该销毁和创建内存中的数据库作为设置的一部分,在这种情况下切换提供程序不会有任何改变。我的意思是“对[这个特定测试]的结果不重要”,而不是整个系统,来吧。不过,谢谢你的有用见解。不过,在某些情况下,我们只需要灵活性,这是TestServer在单元测试之上带来的。实际上,我们选择TestServer是因为我们需要测试一个控制器响应,并将其与另一个控制器的请求耦合。你不这样认为吗你认为这可以用一种纯单元测试方法来完成,而不需要TestServer吗?
var mymock = Mock.Of<IMyClass>();
Mock.Get(mymock)
    .Setup(m => m.Method1(It.IsAny<string>())
    .Returns(value: whatever);

var webHostBuilder =
    new WebHostBuilder()
        .UseEnvironment("Testing")
        .UseContentRoot(projectDir)
        .ConfigureTestServices(services => {
            services.RemoveAll<IMyClass>();//Remove previous registration(s) of this service
            services.TryAddTransient<IMyClass>(sp => mymock);
        })
        .UseStartup<Startup>();