Как проверить сервис без точки входа для проверки данных - PullRequest
1 голос
/ 04 июня 2019

Я учусь пользоваться Nunit.

У меня есть интерфейс под названием «IMenuService».У этого интерфейса есть один метод, который предоставляет menuType, он возвращает список запрошенных menuItem.

На самом деле я создал простую реализацию под названием "StaticMenuService", которая содержит два статических меню: admin / user.StaticMenuService не требует никакого репозитория, потому что его данные зашифрованы, поэтому у его конструктора нет параметров.

Я бы хотел протестировать методы «GetMenu (тип MenuType)», используя два списка тестов, которые присутствуют в админ / меню, но я нене знаю, как пройти этот список тестов, так как StaticMenuService не имеет точки ввода данных.

Я думаю, что нужно изменить конструктор «StaticMenuService», добавив два параметра (UserMenu, AdminMenu), но в этом случае я изменяю только реальный классдля создания теста, и я думаю, что это неправильно, не так ли?

Как я могу использовать свои поддельные данные для реализации тестов?

Это то, что я начал

public class MenuServiceTest
    {

        [SetUp]
        public void SetUp()
        {
            List<MenuContainerItem> AdminMenuContainer;
            List<MenuContainerItem> UserMenuContainer;

            MenuPageItem adminPageTest1 = new MenuPageItem()
            {
                Id = "TEST_ADMIN_PAGE_1",
                PageName = "admin test 1",
                Url = "/admin/test1"
            };
            MenuPageItem adminPageTest2 = new MenuPageItem()
            {
                Id = "TEST_ADMIN_PAGE_2",
                PageName = "admin test 2",
                Url = "/admin/test2"
            };

            MenuContainerItem AdminBasePagesTest = new MenuContainerItem()
            {
                Id = "ADMIN_CONTAINER_TEST",
                Icon = "preferences",
                ContainerName = "container test",
                Pages = new List<MenuPageItem>() { adminPageTest1 , adminPageTest2}
            };

            AdminMenuContainerTest = new List<MenuContainerItem>() { AdminBasePagesTest };
            UserMenuContainerTest = new List<MenuContainerItem>();


        }

        [TestCase(MenuType.ADMIN)]
        [TestCase(MenuType.USER)]
        public void IMenuServiceReturnsAlwaysAList(MenuType type)
        {
            //var mockData = new Mock<>
            //how can I pass AdminMenuContainerTest and UserMenuContainerTest to an instance of StaticMenuService?
        }
    }

DataModels

public class MenuPageItem
{
    public string Id { get; set; }
    public string PageName { get; set; }
    public string Url { get; set; }
}


public class MenuContainerItem
{
    public string Id { get; set; }
    public string ContainerName { get; set; }
    public string Icon { get; set; }
    public IList<MenuPageItem> Pages { get; set; }
}

public enum MenuType
{
    ADMIN = 0,
    USER = 1
}

Интерфейсы

public interface IMenuService
{
   IList<MenuContainerItem> GetMenu(MenuType type);
}

StaticMenuService

public class StaticMenuService : IMenuService
    {
        private List<MenuContainerItem> AdminMenuContainer;
        private List<MenuContainerItem> UserMenuContainer;

        public StaticMenuService()
        {
            MenuPageItem adminPageUsers = new MenuPageItem() {
                Id = "ADMIN_PAGE_1",
                PageName = "gestione utenti",
                Url = "/admin/users"
            };
            MenuPageItem adminPageRoles = new MenuPageItem() {
                Id = "ADMIN_PAGE_2",
                PageName = "gestione ruoli",
                Url = "/admin/roles"
            };
            MenuPageItem adminPageUserRoles = new MenuPageItem() {
                Id = "ADMIN_PAGE_3",
                PageName = "gestione utenti - ruoli",
                Url = "/admin/userRoles"
            };

            MenuContainerItem AdminBaseManagerPages = new MenuContainerItem() {
                Id = "ADMIN_CONTAINER",
                Icon = "preferences",
                ContainerName = "Gestione",
                Pages = new List<MenuPageItem>() { adminPageUsers, adminPageRoles, adminPageUserRoles }
            };

            AdminMenuContainer = new List<MenuContainerItem>() { AdminBaseManagerPages };

            UserMenuContainer = new List<MenuContainerItem>();
        }

        public IList<MenuContainerItem> GetMenu(MenuType type)
        {
            if(type == MenuType.ADMIN)
            {
                return AdminMenuContainer.AsReadOnly();
            } 

            if(type == MenuType.USER)
            {
                return UserMenuContainer.AsReadOnly();
            }

            return new List<MenuContainerItem>().AsReadOnly();
        }
    }

Любая помощь, совет или объяснение приветствуется.

Ответы [ 2 ]

2 голосов
/ 04 июня 2019

Что я думаю, это изменить конструктор "StaticMenuService", добавив два параметра (UserMenu, AdminMenu), но в этом случае я изменяю реальный класс только для создания теста, и я думаю, что это неправильно, не так ли?

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

public class StaticMenuService : IMenuService
{
    private List<MenuContainerItem> AdminMenuContainer;
    private List<MenuContainerItem> UserMenuContainer;

    public StaticMenuService(List<MenuContainerItem> adminMenus, List<MenuContainerItem> userMenus)
    {
        AdminMenuContainer = adminMenus;
        UserMenuContainer = userMenus;
    }

    public IList<MenuContainerItem> GetMenu(MenuType type)
    {
        if(type == MenuType.ADMIN)
        {
            return AdminMenuContainer.AsReadOnly();
        } 

        if(type == MenuType.USER)
        {
            return UserMenuContainer.AsReadOnly();
        }

        return new List<MenuContainerItem>().AsReadOnly();
    }
}

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

public class AdminMenus 
{

    public static implicit operator List<MenuContainerItem> (AdminMenus menus) 
    {
        MenuPageItem adminPageUsers = new MenuPageItem() {
            Id = "ADMIN_PAGE_1",
            PageName = "gestione utenti",
            Url = "/admin/users"
        };
        MenuPageItem adminPageRoles = new MenuPageItem() {
            Id = "ADMIN_PAGE_2",
            PageName = "gestione ruoli",
            Url = "/admin/roles"
        };
        MenuPageItem adminPageUserRoles = new MenuPageItem() {
            Id = "ADMIN_PAGE_3",
            PageName = "gestione utenti - ruoli",
            Url = "/admin/userRoles"
        };

        MenuContainerItem AdminBaseManagerPages = new MenuContainerItem() {
            Id = "ADMIN_CONTAINER",
            Icon = "preferences",
            ContainerName = "Gestione",
            Pages = new List<MenuPageItem>() { adminPageUsers, adminPageRoles, adminPageUserRoles }
        };

        return new List<MenuContainerItem>() { AdminBaseManagerPages };
    }

} 

public class UserMenus 
{
    public static implicit operator List<MenuContainerItem> (UserMenus menus) 
    {
        return new List<MenuContainerItem>();
    }
}

Теперь вы можете назвать это так:

var menuService = new StaticMenuService(new AdminMenus(), new UserMenus());

Глядя на то, что имеет StaticMenuServiceстало бы, вы можете заменить сервис на словарь или некоторый поисковый объект , который использует MenuType в качестве ключа и возвращает список элементов контейнера меню.Это избавило бы от необходимости поддерживать операторы if, которые могут стать кошмаром.

0 голосов
/ 04 июня 2019

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

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

Например:

public abstract class MenuService
{
    public MenuService(List<MenuContainerItem>() container)
    {
        // do shared container setup 
    }
}

public class AdminMenuService : MenuService
{
    public AdminMenuService(List<MenuContainerItem>() container) : base(container)
    {
    }
}

И затем:в своем модульном тесте вы могли бы сделать что-то вроде этого:

var adminMenuService = new AdminMenuService()
var userMenuService = new UserMenuService()

[TestCase(adminMenuService)]
[TestCase(userMenuService)]
public void IMenuServiceReturnsAlwaysAList(MenuService menuService)
{
    menuService.getMenu() // test what you expect to happen in all MenuServices
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...