1

第一次使用 AutoQuery,我在实现 AutoQuery 后遇到了单元测试问题。它通过 Swagger 手动测试工作正常。所以我有一个像这样的get方法:

public class ItemService : Service
{
public IAutoQueryDb AutoQuery { get; set; }
private readonly IRepository<Item> itemRepository;

public ItemService(IRepository<Item> itemRepository)
    {
        this.itemRepository = itemRepository;
    }

public ItemResponse Get(FindItems query)
    {
        var response = new ItemResponse();
        var q = AutoQuery.CreateQuery(query, Request);
        q.Where(x => !x.IsDeleted);
        response.Offset = q.Offset.GetValueOrDefault(0);
        response.Total = (int)itemRepository.CountByCondition(q);
        var queryResult = AutoQuery.Execute(query, q).Results;
        foreach (var item in queryResult)
        {
            response.MultipleResult.Add(item.ToDto());
        }
        return response;
    }
}

请求/响应是这样构建的:

[Route("/item/{Id}", "GET")]
public class Items : IReturn<ItemResponse>
{
    public Items() : base()
    {
    }
    public int Id { get; set; }
}

[Route("/item", "GET")]
public class FindItems : QueryDb<Item>
{
    public int[] Ids { get; set; }
    public string NameContains { get; set; }
}
public class ItemResponse : BaseResponse<ItemDto>
{
    public ItemResponse()
    {
        MultipleResult = new List<ItemDto>();
    }
}

和测试:

public void GetAllItems()
    {
        SeedDatabase();
        var service = appHost.Container.Resolve<ItemService>();
        var request = new rq.FindItems();
        var response = service.Get(request);
        Assert.NotNull(response);
        Assert.Empty(response.MultipleResult);
    }

问题是 CreateQuery 方法中的 Request 仍然为空(当我运行应用程序时,它已正确填充)。那么我应该在 xunit 测试中做什么才能让 Request 成为正确的对象而不是 null 呢?Ofc 我在测试执行时得到空异常。是否有任何机制来预设请求?谢谢你的帮助。

//////更新:我尝试了使用内置客户端建议的不同方法:

[Fact]
    public void CanGetAll()
    {
        var client = new JsonHttpClient(BaseUri);
        var all = client.Get(new FindItem());
        Assert.Empty(all.Results);
    }

Request 不再为 null,但 CreateQuery 仍返回 null。我觉得我仍然缺少一个或几个参数,但我不知道在哪里。当我通过 IIS 运行应用程序时,我比较了 Request 对象和为单元测试创​​建的对象,它们看起来很相似,但并不相同。

//////解决方案
JsonServiceClient 终于工作了。我需要将 AQ 插件添加到测试设置类并将结果属性添加到响应类中以将结果传递给 QueryResponse 实例。根本不需要更改内置的 JasonServiceClient,默认参数就可以了。我无法根据 BasicRequest 使其工作。但我得到了我需要的东西,这已经足够了。

4

1 回答 1

1

注意:像AutoQuery这样依赖于IRequest上下文的服务最好由集成测试而不是单元测试来提供,但您可以使用它BasicRequest来注入一个空的 IRequest,例如:

var service = appHost.Container.Resolve<ItemService>();
service.Request = new BasicRequest();

此外,许多 ServiceStack 功能都希望运行已配置的 AppHost,请参阅内存数据库单元测试,了解如何BasicAppHost在测试运行时进行配置。

这是一个自动查询单元测试的示例:

您需要创建自定义 AutoQuery 实现,因为 AutoQuery 只为真实服务创建 AutoQuery 服务:

[Route("/movies")]
public class QueryMovies : QueryDb<Movie>
{
    public string[] Ratings { get; set; }
}

public class MyQueryServices : Service
{
    public IAutoQueryDb AutoQuery { get; set; }

    public object Any(QueryMovies query)
    {
        var q = AutoQuery.CreateQuery(query, base.Request);
        return AutoQuery.Execute(query, q);
    }
}

然后你可以用你想要查询的表来配置你BasicAppHost的内存 SQLite 数据库,例如:AutoQueryFeature

public class AutoQueryUnitTests
{
    private ServiceStackHost appHost;
    public AutoQueryUnitTests()
    {
        appHost = new BasicAppHost {
            ConfigureAppHost = host => {
                host.Plugins.Add(new AutoQueryFeature());
            },
            ConfigureContainer = container => {
                var dbFactory = new OrmLiteConnectionFactory(
                    ":memory:", SqliteDialect.Provider);
                container.Register<IDbConnectionFactory>(dbFactory);
                using (var db = dbFactory.Open()) {
                    db.DropAndCreateTable<Movie>();
                    db.InsertAll(new[] {
                        new Movie { ... },
                    });
                }
                container.RegisterAutoWired<MyQueryServices>();
            },
        }.Init();
    }
    [OneTimeTearDown] public void OneTimeTearDown() => appHost.Dispose();

    [Test]
    public void Can_execute_AutoQueryService_in_UnitTest()
    {
        var service = appHost.Resolve<MyQueryServices>();
        service.Request = new BasicRequest();
        var response = (QueryResponse<Movie>) service.Any(
            new QueryMovies { Ratings = new[] {"G", "PG-13"} });            
        Assert.That(response.Results.Count, Is.EqualTo(5));
    }
}
于 2018-09-25T14:25:45.837 回答