c# - 单元测试 - 添加新产品

标签 c# unit-testing mstest

大家好,我是单元测试的新手。我的场景:我有一个产品业务逻辑层具有以下类和接口(interface)(productproductCategory、接口(interface)IProductRepositoryProductService) 在 productservice 中实现了添加/更新/删除等方法。我想为添加产品时编写单元测试。下面是我的代码,但我不确定我是否做对了。

测试场景
1) 当我添加新产品时检查过期日期是否大于当前日期
2)当我添加新产品时,价格必须大于0
3)不添加删除标志设置为false的产品
4) 当我添加一个产品类别名称时,不应该为 null/empty

如果有人能特别指出断言的正确方向,我将不胜感激。 代码

ProductService 类中的保存方法

   public Boolean save(Product product)
   {
       Boolean flg = false;
       if ( (product.Expire > DateTime.Now && product.Price > 0 )
        && (product.flg =true))
       {

           flg = true;

       }
       return flg;
   }

单元测试

[TestClass()]
public class ProductServiceTests
{
    ProductService Objproductservice;
    List<Product> ProductList;
    Product product1;
    Product product2;
    Product product3;
    DateTime time;
    Boolean flg;

    [TestInitialize]
    public void Setup()
    {
      flg = false;
      product1 = new Product { ProductId = 1, Name = "Ice Cream Ben&Jerry", Description = "Dairy", Expire = DateTime.Now.AddDays(20), DateModified = DateTime.Now, Price = 3.99, flg = true, CatID=2, CategoryName="Dairy" };
      product2 = new Product { ProductId = 1, Name = "Rice Basmati", Description = "Grocery", Expire = DateTime.Now.AddDays(20), DateModified = DateTime.Now, Price = 7.99, flg = false, CatID = 1002, CategoryName = "Grocery" };

    }


    [TestMethod]
    public void when_save_product_expire_date_greater_current_date()
    {

        Objproductservice = new ProductService();
        flg = Objproductservice.save(product1);

        Assert.IsTrue(product1.Expire > DateTime.Now);
        Assert.IsTrue(flg);
    }

    [TestMethod()]
    public void when_save_product_price_greater_than_zero()
    {

        Objproductservice = new ProductService();
        flg = Objproductservice.save(product1);

        Assert.IsTrue(product1.Price > 0);
        Assert.IsTrue(flg);
    }

    [TestMethod]
    public void do_not_save_product_if_delete_flg_isFalse()
    {

        Objproductservice = new ProductService();
        flg = Objproductservice.save(product2);

        Assert.IsFalse(product2.flg);
        Assert.IsFalse(flg);
    }

    [TestMethod]
    public void when_add_product_stock_level_increate()
    {

    }

    [TestMethod]
    public void when_save_product_categoryName_should_not_be_null()
    {

        Objproductservice = new ProductService();
        flg = Objproductservice.save(product1);

        string CategoryName = product1.CategoryName;
        Assert.IsTrue(CategoryName.Length > 0);
        Assert.IsTrue(flg);
    }

}

最佳答案

我建议您关注 Tell Don't Ask原则,而不是询问产品的有效期、价格等 - 告诉他检查自己(顺便说一句,有 IsExpired 是可以的,但考虑禁止为产品设置无效价格):

public class Product
{
    public DateTime Expire { get; set; }
    public decimal Price { get; set; }

    public virtual bool IsExpired
    { 
        get { return Expire > DateTime.Now; }
    }

    public virtual bool IsValid
    {
        get { return !IsExpired && Price > 0; }
    }
}

现在您可以创建不同的过期或价格无效的产品并将它们传递给服务:

ProductService service;
Mock<IProductRepository> repositoryMock;
Mock<Product> productMock;

[TestInitialize]
public void Setup()
{      
    repositoryMock = new Mock<IProductRepository>();
    service = new ProductService(repositoryMock.Object);
    productMock = new Mock<Product>();
}

[TestMethod]
public void Should_not_save_invalid_product()
{
    productMock.SetupGet(p => p.IsValid).Returns(false);
    bool result = service.save(productMock.Object);

    Assert.False(result);
    repositoryMock.Verify(r => r.Save(It.IsAny<Product>()),Times.Never());
}

[TestMethod]
public void Should_save_valid_product()
{
    productMock.SetupGet(p => p.IsValid).Returns(true); 
    repositoryMock.Setup(r => r.Save(productMock.Object)).Returns(true);

    bool result = service.save(productMock.Object);

    Assert.True(result);
    repositoryMock.VerifyAll();
}  

服务的实现如下所示:

public bool save(Product product)
{
    if (!product.IsValid)
        return false;

    return repository.Save(product);
}

接下来为 Product 编写测试以验证 IsValid 是否正常工作。您可以使用允许模拟静态成员的单元测试框架(例如 TypeMock ),或者您可以使用 Factory 创建产品并向它们注入(inject) ITimeProvider 实现。这将允许您模拟时间提供者。或者很好的组合解决方案 - 创建您自己的允许设置值的静态时间提供程序:

public static class TimeProvider
{        
    private static Func<DateTime> currentTime { get; set; }

    public static DateTime CurrentTime
    {
        get { return currentTime(); }
    }

    public static void SetCurrentTime(Func<DateTime> func)
    {
        currentTime = func;
    }
}

使用此提供程序而不是 DateTime.Now:

public virtual bool IsExpired
{ 
    get { return Expire > TimeProvider.CurrentTime; }
}

现在您可以提供当前时间并为产品编写测试:

private DateTime today;

[TestInitialize]
public void Setup()
{      
    today = DateTime.Today;
    TimeProvider.SetCurrentTime(() => today);
}

[TestMethod]
public void Should_not_be_valid_when_price_is_negative()
{
    Product product = new Product { Price = -1 };
    Assert.False(product.IsValid);
}

[TestMethod]
public void Should_be_expired_when_expiration_date_is_before_current_time()
{        
    Product product = new Product { Expire = today.AddDays(-1) };
    Assert.False(product.IsExpired);
}

// etc

关于c# - 单元测试 - 添加新产品,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22322835/

相关文章:

unit-testing - Grails 单元测试 Buggy 动态查找器

unit-testing - 如何对 Grails 的消息标签进行单元测试

c# - 如何使用 C# 使用 MsTest 对属性进行单元测试?

c# - MSTest 中的 runsettings 和 testsettings 到底有什么区别

c# - 在回调模拟设置中设置 ManualResetEvent 时出错

c# - 为什么 C# 中的内置类型是语言关键字?

c# - 实时播放充满pcm值的数组

C# + LINQ + ADO.NET EF,加入 2 个表并返回所有内容,无需手动指定所有字段

visual-studio-2008 - Visual Studio 2008 测试 View 面板未显示所有测试

c# - 单词拆分算法为前缀词干和后缀