Как исключить другую логику и улучшить производительность юнит-тестов - PullRequest
0 голосов
/ 12 января 2019

Я пытаюсь улучшить производительность модульных тестов в моем проекте. Если я пишу тест в одной логике, мне нужно написать другую логику в моем тесте. Я воспроизвожу это так: У меня есть класс ProductInfo

    public class ProductInfo
{
    public string Name { get; set; }
    public string Title { get; set; }
}

А класса Продукт:

 public class Product
{
    public ProductInfo Info { get; set; }

    private decimal price;
    public decimal Price
    {
        get
        {
            return price;
        }
        set
        {
            price = value;
            Info.Title = $"{Info.Name}-{price} USD";
        }
    }
}

Я создаю юнит-тест для настройки Цена

[TestMethod]
    public void ProductInfoTitleTest()
    {
        decimal price = 120;
        string productName = "Product1";
        ProductInfo info = new ProductInfo() { Name = productName };
        Product product = new Product() { Info = info };
        product.Price = price;
        Assert.AreEqual($"{productName}-{price} USD", product.Info.Title, "Both should be equal");
    }

Создан тестовый проход. Итак, я создаю еще одно свойство в классе Product:

public int Quantity { get; set; }

    public decimal TotalPrice
    {
        get
        {
            return Price * Quantity;
        }
    }

Затем я создаю тест для тестирования TotalPrice:

    [TestMethod]
    public void ProductTotalPriceTest()
    {
        Product product = new Product
        {
            Price = 100,
            Quantity = 2
        };
        Assert.AreEqual(200, product.TotalPrice, "It should be 200");
    }

Этот тест не пройден, потому что я не установил информацию о продукте. Итак, я делаю это:

 [TestMethod]
    public void ProductTotalPriceTest()
    {
        Product product = new Product
        {
            Info = new ProductInfo(),
            Price = 100,
            Quantity = 2
        };
        Assert.AreEqual(200, product.TotalPrice, "It should be 200");
    }

Тогда пройти тест. Есть ли способ сделать это без установки информации о продукте (без изменения логики)? Я надеюсь, что я мог понять вариант использования.

Ответы [ 2 ]

0 голосов
/ 12 января 2019

Как исключить другую логику

Вы не должны . Допустимый экземпляр ProductInfo является частью "контракта" класса Product.

Я бы даже предложил сделать аргумент ProductInfo конструктора, чтобы явно показать потребителям класса, что без него класс не будет работать должным образом.

Если конфигурация тестируемого класса усложняется, создайте вспомогательные / конструкторские классы / функции, где логика для конфигурации останется на том же месте.

Например:

public class ProductBuilder
{
    private string _productName;
    private decimal _price;
    private int _quantity;

    public ProductBuilder ProductName(string name)
    {
        _productName = name;
        return this;
    }

    public ProductBuilder Price(decimal price)
    {
        _price = price;
        return this;
    }

    public ProductBuilder Quantity(int quantity)
    {
        _quantity = quantity;
        return this;
    }

    public Product Create()
    {
        return new Product
        {
            Info = new ProductInfo { Name = _productName },
            Price = _price,
            Quantity = _price, 
        }
    }
}

Тогда в тестах вы сможете создать действительный экземпляр типа Product.

[TestMethod]
public void InfoTitel_ReturnsProductNameAndPrice()
{
    var builder = new ProductBuilder();

    var product = builder.ProductName("Device X").Price(100).Create();

    product.Info.Title.Should().Be("Device X-100.00 USD");
}

[TestMethod]
public void TotalPrice_CalculatesFromPriceAndQuantity()
{
    var builder = new ProductBuilder();

    var product = builder.Price(35.99m).Quantity(2).Create();

    product.TotalPrice.Should().Be(71.98m);
}

Инкапсулируя конфигурацию в выделенный класс, вы сможете изменять логику конфигурации, не затрагивая каждый тест. Если, конечно, вы не измените публичный контракт класса.

0 голосов
/ 12 января 2019

Это похоже на хорошую возможность использовать инициализатор теста для создания экземпляра Product с ProductInfo перед каждым тестом, а затем просто изменить его при необходимости.

[TestClass]
public class ProductTests
{
    Product product;

    [TestInitialize]
    public void Setup()
    {
        product = new Product { Info = new ProductInfo() };
    }

    [TestMethod]
    public void ProductInfoTitleTest()
    {
        decimal price = 120;
        string productName = "Product1";
        product.Info.Name = productName;
        product.Price = price;
        Assert.AreEqual($"{productName}-{price} USD", product.Info.Title, "Both should be equal");
    }

    [TestMethod]
    public void ProductTotalPriceTest()
    {
        product.Price = 100;
        product.Quantity = 2;
        Assert.AreEqual(200, product.TotalPrice, "It should be 200");
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...