如果没有对应的web api模板,首先使用nuget进行安装
例子1:
ProductController 是以硬编码的方式使用StoreAppContext类的实例,可以使用依赖注入模式,在外部指定上下文实例
1 public interface IStoreAppContext:IDisposable 2 { 3 DbSet<Product> Products { get; set; } 4 int SaveChanges(); 5 void MarkAsModified(Product item); 6 } 7 8 public class StoreAppContext : DbContext,IStoreAppContext 9 { 10 // You can add custom code to this file. Changes will not be overwritten. 11 // 12 // If you want Entity Framework to drop and regenerate your database 13 // automatically whenever you change your model schema, please use data migrations. 14 // For more information refer to the documentation: 15 // http://msdn.microsoft.com/en-us/data/jj591621.aspx 16 17 public StoreAppContext() : base("name=StoreAppContext") 18 { 19 } 20 21 public DbSet<Product> Products { get; set; } 22 23 public void MarkAsModified(Product item) 24 { 25 Entry(item).State = EntityState.Modified; 26 } 27 } 28 29 public class ProductsController : ApiController 30 { 31 private IStoreAppContext db = new StoreAppContext(); 32 33 public ProductsController() { } 34 35 public ProductsController(IStoreAppContext context) 36 { 37 db = context; 38 } 39 // GET: api/Products 40 public IQueryable<Product> GetProducts() 41 { 42 return db.Products; 43 } 44 45 // GET: api/Products/5 46 [ResponseType(typeof(Product))] 47 public IHttpActionResult GetProduct(int id) 48 { 49 Product product = db.Products.Find(id); 50 if (product == null) 51 { 52 return NotFound(); 53 } 54 55 return Ok(product); 56 } 57 58 // PUT: api/Products/5 59 [ResponseType(typeof(void))] 60 public IHttpActionResult PutProduct(int id, Product product) 61 { 62 if (!ModelState.IsValid) 63 { 64 return BadRequest(ModelState); 65 } 66 67 if (id != product.Id) 68 { 69 return BadRequest(); 70 } 71 72 db.MarkAsModified(product); 73 74 try 75 { 76 db.SaveChanges(); 77 } 78 catch (DbUpdateConcurrencyException) 79 { 80 if (!ProductExists(id)) 81 { 82 return NotFound(); 83 } 84 else 85 { 86 throw; 87 } 88 } 89 90 return StatusCode(HttpStatusCode.NoContent); 91 } 92 93 // POST: api/Products 94 [ResponseType(typeof(Product))] 95 public IHttpActionResult PostProduct(Product product) 96 { 97 if (!ModelState.IsValid) 98 { 99 return BadRequest(ModelState); 100 } 101 102 db.Products.Add(product); 103 db.SaveChanges(); 104 105 return CreatedAtRoute("DefaultApi", new { id = product.Id }, product); 106 } 107 108 // DELETE: api/Products/5 109 [ResponseType(typeof(Product))] 110 public IHttpActionResult DeleteProduct(int id) 111 { 112 Product product = db.Products.Find(id); 113 if (product == null) 114 { 115 return NotFound(); 116 } 117 118 db.Products.Remove(product); 119 db.SaveChanges(); 120 121 return Ok(product); 122 } 123 124 protected override void Dispose(bool disposing) 125 { 126 if (disposing) 127 { 128 db.Dispose(); 129 } 130 base.Dispose(disposing); 131 } 132 133 private bool ProductExists(int id) 134 { 135 return db.Products.Count(e => e.Id == id) > 0; 136 } 137 }
单元测试代码:
1 public class TestDbSet<T>:DbSet<T>,IQueryable,IEnumerable<T> 2 where T:class 3 { 4 ObservableCollection<T> _data; 5 IQueryable _query; 6 7 public TestDbSet() 8 { 9 _data = new ObservableCollection<T>(); 10 _query = _data.AsQueryable(); 11 } 12 13 public override T Add(T item) 14 { 15 _data.Add(item); 16 return item; 17 } 18 19 public override T Remove(T item) 20 { 21 _data.Remove(item); 22 return item; 23 } 24 25 public override T Attach(T item) 26 { 27 _data.Add(item); 28 return item; 29 } 30 31 public override T Create() 32 { 33 return Activator.CreateInstance<T>(); 34 } 35 36 public override TDerivedEntity Create<TDerivedEntity>() 37 { 38 return Activator.CreateInstance<TDerivedEntity>(); 39 } 40 41 public override ObservableCollection<T> Local 42 { 43 get { return new ObservableCollection<T>(_data); } 44 } 45 46 Type IQueryable.ElementType 47 { 48 get { return _query.ElementType; } 49 } 50 51 System.Linq.Expressions.Expression IQueryable.Expression 52 { 53 get { return _query.Expression; } 54 } 55 56 IQueryProvider IQueryable.Provider 57 { 58 get { return _query.Provider; } 59 } 60 61 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 62 { 63 return _data.GetEnumerator(); 64 } 65 66 IEnumerator<T> IEnumerable<T>.GetEnumerator() 67 { 68 return _data.GetEnumerator(); 69 } 70 } 71 72 class TestProductDbSet:TestDbSet<Product> 73 { 74 public override Product Find(params object[] keyValues) 75 { 76 return this.SingleOrDefault(p=>p.Id==(int)keyValues.Single()); 77 } 78 } 79 80 class TestStoreAppContext : IStoreAppContext 81 { 82 public TestStoreAppContext() 83 { 84 this.Products = new TestProductDbSet(); 85 } 86 87 public System.Data.Entity.DbSet<Product> Products { get; set; } 88 89 90 public int SaveChanges() 91 { 92 return 0; 93 } 94 95 public void MarkAsModified(Product item) 96 { 97 98 } 99 100 public void Dispose() 101 { 102 103 } 104 } 105 106 public class TestProductController 107 { 108 [TestMethod] 109 public void PostProduct_ShouldReturnSameProduct() 110 { 111 var controller = new ProductsController(new TestStoreAppContext()); 112 var item = GetDemoProduct(); 113 114 var result=controller.PostProduct(item) as CreatedAtRouteNegotiatedContentResult<Product>; 115 Assert.IsNotNull(result); 116 Assert.AreEqual(result.RouteName, "DefaultApi"); 117 Assert.AreEqual(result.RouteValues["id"], result.Content.Id); 118 Assert.AreEqual(result.Content.Name, item.Name); 119 } 120 [TestMethod] 121 public void PutProduct_ShouldReturnStatusCode() 122 { 123 var controller = new ProductsController(new TestStoreAppContext()); 124 125 var item = GetDemoProduct(); 126 127 var result = controller.PutProduct(item.Id, item) as StatusCodeResult; 128 Assert.IsNotNull(result); 129 Assert.IsInstanceOfType(result, typeof(StatusCodeResult)); 130 Assert.AreEqual(HttpStatusCode.NoContent, result.StatusCode); 131 } 132 133 [TestMethod] 134 public void PutProduct_ShouldFail_WhenDifferentID() 135 { 136 var controller = new ProductsController(new TestStoreAppContext()); 137 138 var badresult = controller.PutProduct(999, GetDemoProduct()); 139 Assert.IsInstanceOfType(badresult, typeof(BadRequestResult)); 140 } 141 142 [TestMethod] 143 public void GetProduct_ShouldReturnProductWithSameID() 144 { 145 var context = new TestStoreAppContext(); 146 context.Products.Add(GetDemoProduct()); 147 148 var controller = new ProductsController(context); 149 var result = controller.GetProduct(3) as OkNegotiatedContentResult<Product>; 150 151 Assert.IsNotNull(result); 152 Assert.AreEqual(3, result.Content.Id); 153 } 154 155 [TestMethod] 156 public void GetProducts_ShouldReturnAllProducts() 157 { 158 var context = new TestStoreAppContext(); 159 context.Products.Add(new Product { Id = 1, Name = "Demo1", Price = 20 }); 160 context.Products.Add(new Product { Id = 2, Name = "Demo2", Price = 30 }); 161 context.Products.Add(new Product { Id = 3, Name = "Demo3", Price = 40 }); 162 163 var controller = new ProductsController(context); 164 var result = controller.GetProducts() as TestProductDbSet; 165 166 Assert.IsNotNull(result); 167 Assert.AreEqual(3, result.Local.Count); 168 } 169 170 [TestMethod] 171 public void DeleteProduct_ShouldReturnOK() 172 { 173 var context = new TestStoreAppContext(); 174 var item = GetDemoProduct(); 175 context.Products.Add(item); 176 177 var controller = new ProductsController(context); 178 var result = controller.DeleteProduct(3) as OkNegotiatedContentResult<Product>; 179 180 Assert.IsNotNull(result); 181 Assert.AreEqual(item.Id, result.Content.Id); 182 } 183 Product GetDemoProduct() 184 { 185 return new Product() { Id = 3, Name = "Demo name", Price = 5 }; 186 } 187 }
具体的代码参见:Mocking Entity Framework when Unit Testing ASP.NET Web API 2