Эмулировать перечисление наследования: лучший выбор и практика - PullRequest
1 голос
/ 10 февраля 2012

Я разрабатываю тестовое приложение (с использованием NUnit), которое должно будет перемещаться (через Selenium Webdriver API) по веб-страницам. Я хотел бы смоделировать структуру сайта, используя перечисления, чтобы иметь возможность указывать методы, по которым следует перемещаться (особенно методы NUnit) через это перечисление.

this.NavigateTo(Page.HomePage);

Это строгое требование (иметь где-нибудь тип enum) главным образом потому, что NUnit не может быть передан не примитивным типам. Например, этот синтаксис невозможно NUnit, потому что страница должна быть примитивом или перечислением:

static class Page{
  public static Page HomePage;
  public static Page UserAccountPage;
}

/* ... later ... */
[TestCase(Page.HomePage)]
void TestMethod(Page p) { ...

Я также хотел бы использовать тот же enum-or-like для создания базового наследования, как

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()));

Это сложная проблема для меня. Кто-нибудь может помочь?

EDIT: подсказка, как указывает Крис ниже, заключается в том, что NUnit (через атрибуты) может принимать аргумент типа Object. Используя это, возможно, есть способ реализовать объекты, почти не содержащие кода, с моей структурой наследования, и перекодировать часть механизма enum (и ссылку на строки URL).

Не решение моей мечты, но может сработать ...

Ответы [ 2 ]

2 голосов
/ 10 февраля 2012

Вы уверены, что они должны быть примитивами (кстати, мы называем эти типы значений или структуры в мире .net)? Эта страница , кажется, подразумевает, что причина, по которой вы ограничены, связана с внутренними ограничениями атрибутов .NET, которые, в свою очередь, описаны здесь :

Параметры атрибута ограничены постоянными значениями следующие типы:

Простые типы (bool, byte, char, short, int, long, float и double)

строка

System.Type

перечисления

объект (Аргумент к параметру атрибута типа объект должен быть постоянным значением одного из вышеуказанных типов.)

одномерные массивы любого из вышеперечисленных типов

Это подсказывает мне, что будет работать следующее:

static class Pages {
  public const String HomePage = "Home Page";
  public const String UserAccountPage = "User Account Page";
}

[TestCase(Pages.HomePage)]
void TestMethod(Page p) { ...
2 голосов
/ 10 февраля 2012

Вы пытались сделать пользовательский класс вместо перечисления?

, например

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