对Web API进行单元测试,获取相同的ID

本文关键字:获取 ID 单元测试 Web API | 更新日期: 2023-09-27 18:04:33

我在如何写一个单元测试我的web api GET id方法。

我有:

public void GetProduct_ShouldReturnSameID()
{
    var context = new TestModelContext();
    context.Products.Add(GetDemoProduct());
    var controller = new ProductsController(context);
    var result = controller.GetProduct(3) as OkNegotiatedContentResult<Product>;
    Assert.IsNotNull(result);
    Assert.AreEqual(3, result.Content.Id);
}

我要测试的控制器方法是

public IHttpActionResult GetProduct(int id)
{
    var product = (from t in db.Products.Include(t => t.Reviews)
                          .Where(t => t.Id == id)
                          select t);
    if (product == null || product.Count() == 0)
    {
        return NotFound();
    }
    return Ok(product);
}

我的测试工作发现与我的其他控制器,但只是不是这个。我想知道这有什么问题?我的测试失败了

"Expected: not null But was: null"

public class TestModelContext : IModelContext {
    public TestModelContext() {
        this.Products = new TestProductDbSet();
    }
    public DbSet<Product> Products { get; set; }
    public int SaveChanges() {
        return 0;
    }
    public void MarkAsModified(Product item) { }
    public void Dispose() { }
}
public class TestProductDbSet : TestDbSet<Product> {
    public override Product Find(params object[] keyValues) {
        return this.SingleOrDefault(product => product.Id == (int)keyValues.Single());
    }
}
public class TestDbSet<T> : DbSet<T>, IQueryable, IEnumerable<T>
        where T : class
{
    ObservableCollection<T> _data;
    IQueryable _query;
    public TestDbSet()
    {
        _data = new ObservableCollection<T>();
        _query = _data.AsQueryable();
    }
    // ...
    public override T Create()
    {
        return Activator.CreateInstance<T>();
    }
    public override TDerivedEntity Create<TDerivedEntity>()
    {
        return Activator.CreateInstance<TDerivedEntity>();
    }
    public override ObservableCollection<T> Local
    {
        get { return new ObservableCollection<T>(_data); }
    }
    Type IQueryable.ElementType
    {
        get { return _query.ElementType; }
    }
    System.Linq.Expressions.Expression IQueryable.Expression
    {
        get { return _query.Expression; }
    }
    IQueryProvider IQueryable.Provider
    {
        get { return _query.Provider; }
    }
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return _data.GetEnumerator();
    }
    IEnumerator<T> IEnumerable<T>.GetEnumerator()
    {
        return _data.GetEnumerator();
    }
}

GetDemoProduct:

Product GetDemoProduct()
{
    return new Product() { Id = 3, Name = "Name", Reviews = null };
}

对Web API进行单元测试,获取相同的ID

根据示例代码,没有代码路径会导致测试中的方法返回null

它要么返回NotFoundResult要么返回OkNegotiatedContentResult<Product>

假设测试中的方法有可能返回NotFoundResult,如果满足if (product == null || product.Count() == 0)条件并且该方法确实返回未找到的结果,则测试

中的以下内容
...as OkNegotiatedContentResult<Product>;

尝试将NotFoundResult转换为OkNegotiatedContentResult<Product>将导致结果为null

你应该重新检查你的TestModelContext的设置/配置,因为你的linq调用导致product变量为null,从而导致NotFoundResult返回。

更新:

Ok能够根据您更新的详细信息开始测试,并发现了一个我应该早些注意到的问题。

首先,当添加假产品到列表时,我得到一个错误,并且必须更新TestDbSet基类以包含添加的实体。我假设它在示例代码中被省略了。

public override T Add(T entity) {
    _data.Add(entity);
    return entity;
}

在测试方法中的next,给定方法的名称和测试中的期望,它应该返回单个Product。当您在测试中进行强制转换时,您返回的查询也会导致null。

public IHttpActionResult GetProduct(int id) {
    var product = (from t in db.Products.Include(t => t.Reviews)
                          .Where(t => t.Id == id)
                   select t);
    if (product == null || product.Count() == 0) {
        return NotFound();
    }
    return Ok(product.First());
}

经过以上两次修改后,测试如期通过。

看起来控制器返回一个null作为结果。最有可能的是,Products表和/或Reviews表不包含作为参数传递给web方法的值3。

这就是我所怀疑的。返回您正在添加的产品的GetDemoProduct()方法没有Reviews。因此,您的查询:

var product = (from t in db.Products.Include(t => t.Reviews)
                      .Where(t => t.Id == id)
                      select t);

没有返回任何记录。只是一个想法。如果你能给我们看你的GetDemoProduct(),我们就能知道了。