我只想知道怎样才能使这段代码以一种很简单的方式变得更小。
测试
using System;
using Vegan.Test.TestClass;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Data.Entity.Validation;
using System.Linq;
namespace Vegan.Test
{
[TestClass]
public class IngredientsTest
{
[AssemblyInitialize]
public static void AssemblyInitialize(TestContext context)
{
System.Data.Entity.Database.SetInitializer(new DatabaseInitializer());
}
[TestMethod]
public void DeleteIngredient()
{
using (var ctx = new TestDbContext())
{
//Arrange
Ingredient ingredient = new TestClass.Ingredient();
ingredient.Id = 1;
ingredient.Name = "Watermelon";
ingredient.VegeOrVegetarian = VeganType.Both;
//Act
ctx.ingredients.Add(ingredient);
ctx.SaveChanges();
IngredientService service = new IngredientService(ctx);
service.removeIngredient(ingredient.Id);
service.saveChanges();
//Assert
Assert.AreEqual(0, ctx.ingredients.Count());
}
}
[TestMethod]
public void AddIngredient()
{
using (var ctx = new TestDbContext())
{
//Arrange
Ingredient ingredient = new TestClass.Ingredient();
ingredient.Id = 1;
ingredient.Name = "Watermelon";
ingredient.VegeOrVegetarian = VeganType.Both;
//Act
ctx.ingredients.Add(ingredient);
ctx.SaveChanges();
IngredientService service = new IngredientService(ctx);
var TestIngredientList = service.getIngredients();
//Assert
Assert.AreEqual(1, TestIngredientList.Count);
}
}
[TestMethod]
public void AddIngredientWithTooShortName()
{
using (var ctx = new TestDbContext())
{
//Arange
Ingredient ingredient = new Ingredient();
ingredient.Id = 1;
ingredient.Name = "";
ingredient.VegeOrVegetarian = VeganType.Both;
//Act
ctx.ingredients.Add(ingredient);
try
{
ctx.SaveChanges();
}
catch (DbEntityValidationException db)
{
foreach (var validationErrors in db.EntityValidationErrors)
{
foreach (var validationError in validationErrors.ValidationErrors)
{
//Assert
Assert.Fail("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage);
}
}
}
}
}
[TestMethod]
public void AddIngredientWithNullName()
{
using (var ctx = new TestDbContext())
{
//Arrange
Ingredient ingredient = new Ingredient();
ingredient.Id = 1;
ingredient.Name = null;
ingredient.VegeOrVegetarian = VeganType.Both;
ctx.ingredients.Add(ingredient);
//act
try
{
ctx.SaveChanges();
}
catch (DbEntityValidationException db)
{
foreach (var validationErrors in db.EntityValidationErrors)
{
foreach (var validationError in validationErrors.ValidationErrors)
{
//Assert
Assert.Fail("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage);
}
}
}
}
}
}其他类
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Vegan.Test.TestClass
{
public enum VeganType
{
Vegan,
Vegetarian,
Both
};
public class TestDbContext : DbContext,IDisposable
{
public virtual IDbSet<Ingredient> ingredients { get; set; }
}
public class DatabaseInitializer : System.Data.Entity.DropCreateDatabaseAlways<TestDbContext>
{
protected override void Seed(TestDbContext context)
{
context.SaveChanges();
}
}
public class Ingredient
{
public int Id { get; set; }
[Required(ErrorMessage ="Name is required")]
[StringLength(60,ErrorMessage ="Value must be between 3 and 60",MinimumLength =3)]
public String Name { get; set; }
public VeganType VegeOrVegetarian { get; set; }
}
public class IngredientService
{
private readonly TestDbContext _TestDbContext;
public IngredientService(TestDbContext TestDbContext)
{
_TestDbContext = TestDbContext;
}
public List<Ingredient> getIngredients()
{
return _TestDbContext.ingredients.ToList();
}
public void removeIngredient(int id)
{
var toRemove = _TestDbContext.ingredients.Find(id);
_TestDbContext.ingredients.Remove(toRemove);
}
public void saveChanges()
{
_TestDbContext.SaveChanges();
}
}
}发布于 2016-09-12 07:09:01
使代码更小的最好方法是搜索重复码。在您的测试方法中,有很多重复的代码可以提取到其他方法中。
例如,可以将上下文创建和销毁移动到测试初始化和清理方法:
[TestClass]
public class IngredientsTest
{
TestDbContext ctx;
[AssemblyInitialize]
public static void AssemblyInitialize(TestContext context)
{
System.Data.Entity.Database.SetInitializer(new DatabaseInitializer());
}
[TestInitialize]
public void Initialize()
{
ctx = new TestDbContext();
}
[TestCleanup]
public void Cleanup()
{
ctx.Dispose();
}
...
}您可以做的另一件事是创建一个私有方法来创建成分:
Ingredient CreateTestIngredient(int id, string name, VeganType type)
{
Ingredient ingredient = new Ingredient();
ingredient.Id = id;
ingredient.Name = name;
ingredient.VegeOrVegetarian = type;
return ingredient;
}所以现在你的第一个测试应该是这样的:
[TestMethod]
public void DeleteIngredient()
{
var testIngredient = CreateTestIngredient(1, "Watermelon", VeganType.Both);
ctx.ingredients.Add(testIngredient);
ctx.SaveChanges();
var serviceUT = new IngredientService(ctx);
serviceUT.removeIngredient(testIngredient.Id);
serviceUT.saveChanges();
Assert.AreEqual(0, ctx.ingredients.Count());
}注意被测试对象的变量serviceUT。重复,直到所有重复的代码消失。
发布于 2016-09-14 08:27:28
@Carlos Alejo已经介绍了如何删除一些复制。我想补充的是,在单元测试中,在消除所有的重复和仍然让您的测试真正的测试变得清晰之间有一种平衡。尽管如此,我还是会把重点放在你的测试上。
虽然我知道有些人喜欢这样做,但我不倾向于在我的测试中列出不同的步骤(行动、安排、断言)。如果您要添加注释,那么我将非常小心地确保您将其拆分以反映您正在测试的内容。看看你的一个测试:
[TestMethod]
public void DeleteIngredient()
{
using (var ctx = new TestDbContext())
{
//Arrange
Ingredient ingredient = new TestClass.Ingredient();
ingredient.Id = 1;
ingredient.Name = "Watermelon";
ingredient.VegeOrVegetarian = VeganType.Both;
//Act
ctx.ingredients.Add(ingredient);
ctx.SaveChanges();
IngredientService service = new IngredientService(ctx);
service.removeIngredient(ingredient.Id);
service.saveChanges();
//Assert
Assert.AreEqual(0, ctx.ingredients.Count());
}
}这个测试名为‘DeleteIngre产’,这意味着测试的目标是DeleteIngredient调用。设置数据库,包括添加要删除的成分,并将其保存在“安排”步骤中,而不是“法令”步骤中。
您的测试名称并不是特别描述性的。例如,AddIngredientWithNullName。这并没有告诉我对考试的期望。添加一个空名的成分是有效的还是失败的?从名字上看还不清楚,所以我得看一下考试。
由于测试名称不明确,所以不清楚这是否是测试的正确行为,但是,我认为名为AddIngredientWithTooShortName的测试是在测试如果提供的名称太短时会失败。看一下实现,您实际上是在测试:
When Adding an ingredient that has a short name
Ensure that no exceptions are thrown, OR,
IF an exception is thrown that it doesn't contain a Validation Error的级别
我会让一个特定的测试类专注于我想要测试的应用程序的一个级别。目前还不清楚你的班级所关注的水平是什么。在测试服务级调用( Service,AddIngredient)的同时,您似乎正在测试基于DbContext的调用(AddIngredientWithTooShortName)。我会将测试分成不同的类,以便更清楚地了解您正在测试的内容以及测试的原因。
在AddIngredient中,您使用上下文保存一个成分,然后使用一个服务检索它,正如我已经说过的,不清楚哪些元素正在被测试(服务/上下文),但是正在检查返回的记录的数量是1,还是真的应该检查返回的记录是您添加的记录吗?
https://codereview.stackexchange.com/questions/141045
复制相似问题