我正在学习如何使用Nunit。
我有一个名为“ IMenuService”的接口。该接口具有给定menuType的一种方法,它返回所请求的menuItem列表。
实际上,我已经创建了一个名为“ StaticMenuService”的简单实现,其中包含两个静态菜单:admin / user。 StaticMenuService不需要任何存储库,因为它的数据是经过编码的,因此它的构造函数没有参数。
我将使用两个表示admin /菜单的测试列表来测试“ GetMenu(MenuType type)”方法,但是由于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?
}
}
数据模型
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();
}
}
感谢您的帮助,建议或解释。
答案 0 :(得分:2)
我认为是修改“ 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
变成了什么,您可以用dictionary或某些使用MenuType
作为键并返回菜单容器列表的lookup object来代替服务项目。这将消除对if语句的需求,而if语句可能成为噩梦般的维持下去。
答案 1 :(得分:0)
如果我了解您的意思,那么我相信您可能会受益于创建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
}