首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >EntityFramework UnitTest

EntityFramework UnitTest
EN

Code Review用户
提问于 2016-09-10 22:48:16
回答 2查看 244关注 0票数 2

我只想知道怎样才能使这段代码以一种很简单的方式变得更小。

测试

代码语言:javascript
复制
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);
                    }
                }
            }
        }
    }
}

其他类

代码语言:javascript
复制
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();
        }
    }
}
EN

回答 2

Code Review用户

发布于 2016-09-12 07:09:01

使代码更小的最好方法是搜索重复码。在您的测试方法中,有很多重复的代码可以提取到其他方法中。

例如,可以将上下文创建和销毁移动到测试初始化和清理方法:

代码语言:javascript
复制
[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();
    }

    ...
}

您可以做的另一件事是创建一个私有方法来创建成分:

代码语言:javascript
复制
Ingredient CreateTestIngredient(int id, string name, VeganType type)
{
    Ingredient ingredient = new Ingredient();
    ingredient.Id = id;
    ingredient.Name = name;
    ingredient.VegeOrVegetarian = type;

    return ingredient;
}

所以现在你的第一个测试应该是这样的:

代码语言:javascript
复制
[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。重复,直到所有重复的代码消失。

票数 3
EN

Code Review用户

发布于 2016-09-14 08:27:28

@Carlos Alejo已经介绍了如何删除一些复制。我想补充的是,在单元测试中,在消除所有的重复和仍然让您的测试真正的测试变得清晰之间有一种平衡。尽管如此,我还是会把重点放在你的测试上。

AAA

虽然我知道有些人喜欢这样做,但我不倾向于在我的测试中列出不同的步骤(行动、安排、断言)。如果您要添加注释,那么我将非常小心地确保您将其拆分以反映您正在测试的内容。看看你的一个测试:

代码语言:javascript
复制
[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。这并没有告诉我对考试的期望。添加一个空名的成分是有效的还是失败的?从名字上看还不清楚,所以我得看一下考试。

Bug?

由于测试名称不明确,所以不清楚这是否是测试的正确行为,但是,我认为名为AddIngredientWithTooShortName的测试是在测试如果提供的名称太短时会失败。看一下实现,您实际上是在测试:

代码语言:javascript
复制
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

AddIngredient中,您使用上下文保存一个成分,然后使用一个服务检索它,正如我已经说过的,不清楚哪些元素正在被测试(服务/上下文),但是正在检查返回的记录的数量是1,还是真的应该检查返回的记录是您添加的记录吗?

票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/141045

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档