Я новичок в модульном тестировании, и я хотел бы знать, почему он не работает - PullRequest
0 голосов
/ 27 ноября 2018

Я новичок в MVC и модульном тестировании, поэтому я следовал инструкциям и т. Д.

В данный момент я смотрю на модульное тестирование.У меня есть тест, который, насколько я вижу, должен работать, но, к сожалению, не работает.

    using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using WorkingWithVisualStudio.Controllers.Home;
using WorkingWithVisualStudio.Models;
using Xunit;
namespace WorkingWithVisualStudio.Tests
{
    public class HomeControllerTests
    {
        class ModelCompleteFakeRepository : IRepository
        {
            public IEnumerable<Product> Products { get; } = new Product[] {
 new Product { Name = "P1", Price = 275M },
 new Product { Name = "P2", Price = 48.95M },
 new Product { Name = "P3", Price = 19.50M },
 new Product { Name = "P3", Price = 34.95M }};
            public void AddProduct(Product p)
            {
                // do nothing - not required for test
            }
        }
        [Fact]
        public void IndexActionModelIsComplete()
        {
            // Arrange
            var controller = new HomeController();
            controller.Repository = new ModelCompleteFakeRepository();

            // Act
            var model = (controller.Index() as ViewResult)?.ViewData.Model
            as IEnumerable<Product>;
            // Assert
            Assert.Equal(controller.Repository.Products, model,
            Comparer.Get<Product>((p1, p2) => p1.Name == p2.Name
            && p1.Price == p2.Price));
        }
        class ModelCompleteFakeRepositoryPricesUnder50 : IRepository
        {
            public IEnumerable<Product> Products { get; } = new Product[] {
 new Product { Name = "P1", Price = 5M },
 new Product { Name = "P2", Price = 48.95M },
 new Product { Name = "P3", Price = 19.50M },
 new Product { Name = "P3", Price = 34.95M }};
            public void AddProduct(Product p)
            {
                // do nothing - not required for test
            }
        }
        [Fact]
        public void IndexActionModelIsCompletePricesUnder50()
        {
            // Arrange
            var controller = new HomeController();
            controller.Repository = new ModelCompleteFakeRepositoryPricesUnder50();
            // Act
            var model = (controller.Index() as ViewResult)?.ViewData.Model
            as IEnumerable<Product>;
            // Assert
            Assert.Equal(controller.Repository.Products, model,
            Comparer.Get<Product>((p1, p2) => p1.Name == p2.Name
            && p1.Price == p2.Price));
        }
    }
}

Когда я запускаю IndexActionModelIsCompletePricesUnder50 (), я получаю следующее:

Message: Assert.Equal() Failure
Expected: Product[] [Product { Name = "P1", Price = 5 }, Product { Name = "P2", Price = 48.95 }, Product { Name = "P3", Price = 19.50 }, Product { Name = "P3", Price = 34.95 }]
Actual:   ValueCollection<String, Product> [Product { Name = "Kayak", Price = 275 }, Product { Name = "Lifejacket", Price = 48.95 }, Product { Name = "Soccer ball", Price = 19.50 }, Product { Name = "Corner flag", Price = 34.95 }]

MyМодель выглядит следующим образом:

public class Product
    {
        public string Name { get; set; }
        public decimal Price { get; set; }
    }

Мой репозиторий:

public class SimpleRepository : IRepository
    {
        private static SimpleRepository sharedRepository = new SimpleRepository();
        private Dictionary<string, Product> products = new Dictionary<string, Product>();

        public static SimpleRepository SharedRepository => sharedRepository;

        public SimpleRepository()
        {
            var initialItems = new[]
            {
                new Product {Name = "Kayak", Price = 275M},
                new Product { Name = "Lifejacket", Price = 48.95M },
                new Product { Name = "Soccer ball", Price = 19.50M },
                new Product { Name = "Corner flag", Price = 34.95M }
            };
            foreach(var p in initialItems)
            {
                AddProduct(p);
            }
            //products.Add("Error", null);
        }

        public IEnumerable<Product> Products => products.Values;

        public void AddProduct(Product p) => products.Add(p.Name, p);
    }

Мой интерфейс репозитория

public interface IRepository
{
    IEnumerable<Product> Products { get; }
    void AddProduct(Product p);
}

Мой компаратор:

public class Comparer
{
    public static Comparer<U> Get<U>(Func<U, U, bool> func)
    {
        return new Comparer<U>(func);
    }
}
public class Comparer<T> : Comparer, IEqualityComparer<T>
{
    private Func<T, T, bool> comparisonFunction;

    public Comparer(Func<T, T, bool> func)
    {
        comparisonFunction = func;
    }

    public bool Equals(T x, T y)
    {
        return comparisonFunction(x, y);
    }

    public int GetHashCode(T obj)
    {
        return obj.GetHashCode();
    }
}

мой контроллер:

public class HomeController : Controller
{
    public IRepository Repository = SimpleRepository.SharedRepository;

    public IActionResult Index() => View(SimpleRepository.SharedRepository.Products);

    [HttpGet]
    public IActionResult AddProduct() => View(new Product());

    [HttpPost]
    public IActionResult AddProduct(Product p)
    {
        Repository.AddProduct(p);
        return RedirectToAction("Index");
    }
}

Извините, если это кажется глупым вопросом, но я только начал изучать юнит-тестирование.Если бы кто-то мог объяснить мне, в чем проблема, я определенно был бы признателен.Большое спасибо тем, кто нашел время протянуть руку.

Ответы [ 2 ]

0 голосов
/ 27 ноября 2018

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

Методы и классы должны явно требоваться (обычно через параметры метода или конструктор)параметры) любые взаимодействующие объекты, в которых они нуждаются для правильного функционирования.

Таким образом, контроллер в конечном итоге будет выглядеть следующим образом

public class HomeController : Controller {
    private readonly IRepository repository;

    public HomeController(IRepository repository) {
        this.repository = repository;
    }

    public IActionResult Index() => View(repository.Products.ToList());

    [HttpGet]
    public IActionResult AddProduct() => View(new Product());

    [HttpPost]
    public IActionResult AddProduct(Product p) {
        repository.AddProduct(p);
        return RedirectToAction("Index");
    }
}

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

Старайтесь избегать тесной связи ваших классов со статическими или общими зависимостями.Было бы безопаснее внедрить абстракцию этой зависимости.

Теперь можно легко выполнить упрощенную версию теста следующим образом.

class ModelCompleteFakeRepository : IRepository {
    public IEnumerable<Product> Products { get; } = new Product[] {
        new Product { Name = "P1", Price = 275M },
        new Product { Name = "P2", Price = 48.95M },
        new Product { Name = "P3", Price = 19.50M },
        new Product { Name = "P3", Price = 34.95M }
    };

    public void AddProduct(Product p) {
        // do nothing - not required for test
    }
}

[Fact]
public void IndexActionModelIsComplete() {
    // Arrange
    var repository = new ModelCompleteFakeRepository();
    var controller = new HomeController(repository);
    var expected = repository.Products;

    // Act
    var actual = (controller.Index() as ViewResult)?.ViewData.Model as IEnumerable<Product>;

    // Assert
    Assert.IsNotNull(actual);
    Assert.Equal(expected, actual);
}
0 голосов
/ 27 ноября 2018

Поскольку в вашем методе Index вы ссылаетесь на SimpleRepository, а не на Repository участника.

Замените

public IActionResult Index() => View(SimpleRepository.SharedRepository.Products);

на

public IActionResult Index() => View(Repository.Products);

Я должен также добавить, что вы, возможно, захотите взглянуть на структуру вашего кода и вместо этого внедрить хранилище в конструктор.Кроме того, два разных теста у вас проверяют одно и то же, поэтому необходим только один из них.

Редактировать: Мои ответы решают вашу текущую проблему, в то время как ответ @Nkosi показывает, как вы должны сделать это правильно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...