对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 };
}
根据示例代码,没有代码路径会导致测试中的方法返回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()
,我们就能知道了。