模拟枚举继承:最佳选择和实践



我正在设计一个测试应用程序(使用NUnit),该应用程序必须在网页中导航(通过Selenium Webdriver API)。我想使用枚举对站点结构进行建模,以便能够通过这个枚举告诉方法在哪里导航(尤其是NUnit方法)。

this.NavigateTo(Page.HomePage);

这是一个强烈的要求(在某个地方有一个枚举类型),主要是因为不能向NUnit传递非基元类型。例如,这种语法对NUnit来说是不可能的,因为Page必须是原语或enum:

static class Page{
  public static Page HomePage;
  public static Page UserAccountPage;
}
/* ... later ... */
[TestCase(Page.HomePage)]
void TestMethod(Page p) { ...

我还想使用相同的枚举或类似的方法来进行基本的继承,比如

interface IPage{}
interface IPageNavigatable : Page {}
interface IPageUserRelated : Page {}
interface IWildcardPage : Page {}
enum Page{
  HomePage : IPageNavigatable,
  UserAccountPage : IPageNavigatable IPageUserRelated,
  ErrorPage : /* none */,
  AnyPage : IWildcardPage 
}

然后,我将能够做出像这样非常有趣的方法

bool IsCurrentPage(IWildcardPage p);
void LoginThenNavigate(String user, String pw, IPageUserRelated p);
Page WhereAmI(); /* and use this value with IsAssignableFrom */

我知道C#禁止枚举继承(我仍然不理解这个选择,但现在这不是我的问题),我已经阅读了一些解决方案,包括一个从头开始重写枚举机制的类;没有一个看起来令人满意。

我的最佳想法是使用一个带有内部枚举和一些公共布尔值的复杂类。不是很满意。。。

public class Page{
  enum Pages { /* you know them */}
  public Page.Pages InnerPage;
  public bool isWildcard, isUserRelated, ...;
  public Page(Page.Pages p){
    this.InnerPage = p;
    switch (p){
      case ...:
      case ...:
        this.isWildcard = true;
        break;
      /* ... */
    }
  }
}
/* NUnit calls */
[TestCase(Page.Pages.HomePage)]
void TestMethod(Page.Pages p) { ...

此外,在一个完美的世界里,我很乐意将我的枚举或其他类型的值与字符串或URI"链接"起来,这样我就可以写一些类似的东西:

enum Page{
  HomePage : IPageNavigatable = "/index.php",
  UserAccountPage : IPageNavigatable IPageUserRelated = "/user.php",
  ErrorPage : /* none */ = (String) null,
  AnyPage : IWildcardPage = (String) null
}
/* ... */
Page p;
Selenium.Webdriver drv;
drv.Navigate().GoToUrl(new Url(p.ToString()));

这对我来说是个难题。有人能帮忙吗?

编辑:正如Chris在下面指出的,一条线索是NUnit(通过属性)可以接受Object类型的参数。使用它,可能有一种方法可以用我的继承结构实现几乎没有代码对象,并重新编码枚举机制的一部分(以及URL字符串的链接)。

不是我梦想中的解决方案,但可能会奏效。。。

你确定它们必须是基元吗(顺便说一句,我们在.net世界中称这些值类型或结构)?这个页面似乎意味着你受到限制的原因是.NET属性中固有的限制,而这些属性又在这里描述:

属性参数被限制为以下类型:

简单类型(bool、byte、char、short、int、long、float和double)

字符串

系统类型

enums

对象(对象类型的属性参数的自变量必须是上述类型之一的常数值。)

任何上述类型的一维阵列

这向我表明以下方法可行:

static class Pages {
  public const String HomePage = "Home Page";
  public const String UserAccountPage = "User Account Page";
}
[TestCase(Pages.HomePage)]
void TestMethod(Page p) { ...

您是否尝试过只做自定义类而不是枚举?

public class Page
{
    public IPageNavigatable HomePage = "/index.php";
    public IPageNavigatable UserAccountPage  = "/user.php";
    public Type ErrorPage = null;
    public IWildcardPage AnyPage  = null;
}

最新更新