c# - 伪造来自测试的 GetAsync 调用
问题描述
public Fixture()
{
_server = new TestServer(new WebHostBuilder()
.UseStartup<Startup>()
.ConfigureServices(services =>
{
services.AddScoped<ICarService, CarService>();
}));
Client = _server.CreateClient();
}
从测试我用它HttpClient
来测试我的API。
using (var response = await _client.GetAsync($"/api/car/{id}"))
{
//...
}
问题是我想GetAsync(int id)
在CarService
课堂上伪造方法的结果。
所以我尝试了
var myCarObject = ... omitted for clarity
var myCarMockService = new Mock<ICarService>();
myCarMockService.Setup(x => x.GetAsync(It.IsAny<int>())).Returns(Task.FromResult(myCarObject));
我不知道这是正确的方法,但如果是这样,我如何将它注入到Fixture
课堂中以便CarService
可以使用它。
public class CarService: ICarService {
private readonly CarDbContext _carDbContext;
public CarService(CarDbContext carDbContext)
{
_carDbContext = carDbContext;
}
public async Task<Car> GetAsync(int id)
{
return await _carDbContext.Cars.FindAsync(id);
}
}
更新:
private readonly ICarService _carService;
public CarController(ICarService carService)
{
_carService = carService;
}
public async Task<IActionResult> Get([FromRoute] int id)
{
var car = await _carService.GetAsync(id);
}
更新 2:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<CarDbContext>(options => { options.UseSqlServer(Configuration.GetConnectionString("Db")); });
services.AddTransient<ICarService, CarService>();
}
}
public class CarService : ICarService
{
private readonly CarDbContext _carDbContext;
public ContactService(CarDbContext carDbContext)
{
_carDbContext= carDbContext;
}
public async Task<Owner> GetAsync(int ownerId)
{
var owner = await _carDbContext.Owners.FindAsync(ownerId);
return owner.Car;
}
}
更新 3:
private readonly TestServer _server;
public Fixture()
{
var dbContextOptions = new DbContextOptionsBuilder<CarDbContext>()
.UseInMemoryDatabase(Guid.NewGuid().ToString())
.Options;
var mockContext = new Mock<CarDbContext>(dbContextOptions);
var mockOwnerSet = new Mock<DbSet<Owner>>();
var mockCarSet = new Mock<DbSet<Car>>();
mockContext.Setup(m => m.Owners).Returns(mockOwnerSet.Object);
mockContext.Setup(m => m.Cars).Returns(mockCarSet.Object);
var carService = new CarService(mockContext.Object);
_server = new TestServer(new WebHostBuilder()
.ConfigureAppConfiguration((context, conf) =>
{
conf.AddJsonFile(@Directory.GetCurrentDirectory() + "../appsettings.json");
}).UseStartup<Startup>()
.ConfigureServices(services =>
{
services.AddDbContext<CarDbContext>(options => options.UseInMemoryDatabase("Test"));
services.AddScoped<ICarService>(_ => carService);
})
);
Client = _server.CreateClient();
}
解决方案
配置测试服务器以使用模拟服务
public Fixture() {
Car myCarObject = //... omitted for brevity
var myCarMockService = new Mock<ICarService>();
myCarMockService
.Setup(x => x.GetAsync(It.IsAny<int>()))
.ReturnsAsync(myCarObject);
_server = new TestServer(new WebHostBuilder()
.UseStartup<Startup>()
.ConfigureTestServices(services => {
var serviceDescriptor = services.FirstOrDefault(descriptor => descriptor.ServiceType == typeof(ICarService));
if (serviceDescriptor != null) services.Remove(serviceDescriptor);
services.AddTransient<ICarService>(_ => myCarMockService.Object); // <-- NOTE
})
);
Client = _server.CreateClient();
}
这样,当进行调用时,模拟服务将按预期注入。
推荐阅读
- r - 我有一个面板数据集,每年有多个观察值,我如何计算每年 obs 的总和而不对“年份”变量求和?
- java - Jackson ObjectMapper 两次用不同的值写入对象
- laravel - 后续npm操作遇到权限问题
- php - PHP 简单的网络套接字
- azure-pipelines - 通过 Azure 管道发布 vsts 扩展时出错
- angular - 在哪里保存电子商务网站的购物车 - Angular
- vba - 用于更新股票图表的动态范围的 VBA 代码
- c - 有没有办法摆脱这个开关并把它变成一个更小的代码块?
- azure - 带有 Azure VPN 网关的 OpenVPN 至少每分钟断开一次
- reactjs - 为什么这个调度动作在反应组件中不起作用?