Инструменты .NET: извлечение интерфейса и реализация класса-оболочки

Есть ли инструмент, который может генерировать извлечение и генерировать интерфейсы для существующих классов?

Я знаю, что Visual Studio извлечет интерфейс для существующего класса. Однако я также хотел бы создать класс-оболочку, реализующий эту функциональность.

Я считаю, что это очень помогло бы для модульного тестирования.

Пример существующего класса:

public class ThirdPartyClass
{
   public void Method1(){}
   public void Method2(){}
}

Это может быть создано Visual Studio (Extract Interface):

public interface IThirdPartyClass
{
   void Method1();
   void Method2();
}

Я хотел бы сделать еще один шаг вперед:

public class ThirdPartyClassWrapper : IThirdPartyClass
{
   private tpc = new ThirdPartyClass();
   public void Method1()
   {
       tpc.Method1();
   }
   public void Method2()
   {
       tpc.Method2();
   }
}

Обновление:

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


person Community    schedule 17.02.2011    source источник
comment
любое решение по этому поводу ??   -  person Kiquenet    schedule 29.12.2011
comment
Зашел сюда в поисках точно такого же ответа. Я голосую за вопрос.   -  person Jazz    schedule 28.11.2012
comment
Повторное голосование. EF или VS должны иметь эту опцию.   -  person NoobDeveloper    schedule 21.07.2013


Ответы (5)


Нашел способ обойти это для незапечатанных классов.

1 - Наследовать от внешнего класса

class MyWrapper : ExternalClass

2 - Извлечь интерфейс для всех публичных методов

class MyWrapper : ExternalClass, IExternalClass

3 - Удалить наследование от внешнего класса

class MyWrapper : IExternalClass

4 - Вы получите подсказку в имени класса о членах из интерфейса, которые не реализуются. Alt + Enter на нем и пусть Resharper автоматически реализует их

5. Используйте этот шаблон кода для переноса свойств

    get { return $INNERCOMPONENT$.$NAME$; }
    set { $INNERCOMPONENT$.$NAME$ = value; }

6. Используйте этот шаблон кода для переноса методов

return $INNERCOMPONENT$.$NAME$($SIGNATURE$);
person Jazz    schedule 28.11.2012

Я не знаю инструмента, который сделал бы это за вас.

Вы, наверное, знаете, но Visual Studio идет на полшага дальше — она может обеспечить пустую реализацию интерфейса. Я бы остановился на этом, если это одноразовая задача.

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

person Alexei Levenkov    schedule 17.02.2011

Еще один действительно удобный способ сделать это — использовать Resharper для создания «делегирующих членов», как описано здесь: https://stackoverflow.com/a/2150827/1703887

Шаги:

  1. Создайте новый класс, который наследуется от класса, который вы хотите обернуть частной переменной типа этого класса:

    public class ThirdPartyClassWrapper : ThirdPartyClass
    {
        private ThirdPartyClass _ThirdPartyClass;
    }
    
  2. Сделайте Alt-Insert в/в классе, чтобы использовать Resharper для создания «Делегирования членов». Выберите методы, которые вы хотите открыть и передать в приватную переменную.

  3. Если у вас установлена ​​бесплатная версия расширения GhostDoc GhostDoc, может выделить все созданные свойства, методы и т. д. и выполнить Ctrl-D, чтобы автоматически получить всю документацию из базового класса и поместить ее в новые члены. (Resharper тоже может это сделать, но я думаю, вам нужно будет поставить «новый» для каждого элемента, что позволит вам нажать Alt-Enter и выбрать «Добавить комментарии xml-doc» во всплывающем меню Resharper).

  4. Затем вы можете удалить базовый класс и выполнить некоторую дополнительную очистку на случай, если сигнатуры метода/свойства выставят какие-либо другие типы, которые вам нужно обернуть.

person csrowell    schedule 06.02.2015

То, что вы ищете, это заглушка, это можно сделать либо путем создания собственной реализации заглушки интерфейса, либо с помощью фиктивной среды, такой как Rhinomocks. Обертывание сложного класса в другой класс для целей тестирования не принесет вам никакой пользы.

С уважением Мортен

person Morten    schedule 17.02.2011
comment
Обертывание сложного класса в другой класс для целей тестирования не принесет вам никакой пользы. Я думаю, что это уменьшило бы связанность и позволило бы реализовать индивидуальную реализацию позже в будущем. - person ; 18.02.2011
comment
Да, но почему бы пока не заглушить интерфейс и не использовать его для ваших тестов? Если вы используете реализацию, вы также тестируете ее, делая свой тест интеграционным. - person Morten; 18.02.2011
comment
Правда, я бы не стал тестировать против ThirdPartyClassWrapper, я бы заглушил интерфейс. Однако я не могу заглушить статический класс. Помимо тестирования, я думаю, что это действительно принесет пользу позже в будущем. - person ; 18.02.2011
comment
Если входной класс является статическим, вы можете внедрить статические функции через делегаты. Таким образом, использование метода в статическом классе может быть заменено нестатической/заглушенной реализацией при тестировании. - person Morten; 18.02.2011

Я настоятельно рекомендую вам изучить мок-фреймворк, такой как Fakeiteasy.

Но чтобы дать вам именно то, что вы просили, смотрите ниже. Я подозреваю, что у ReSharper не было этой операции, когда другие ответили.

  1. добавьте интерфейс в класс, который вы хотите использовать в качестве класса-оболочки

    class MyWebElement : IWebElement { }
    

  1. Найдите/щелкните «Делегировать реализацию YourInterfaceHere» в новое поле Делегирование реализации

  1. Выберите параметры Параметры делегирования

  1. Нажмите «Готово» и наслаждайтесь новым классом.

    class MyWebElement : IWebElement
    {
        private IWebElement _webElementImplementation;
        public IWebElement FindElement(By @by)
        {
            return _webElementImplementation.FindElement(@by);
        }
    
        public ReadOnlyCollection<IWebElement> FindElements(By @by)
        {
            return _webElementImplementation.FindElements(@by);
        }
    
        public void Clear()
        {
            _webElementImplementation.Clear();
        }
    
        public void SendKeys(string text)
        {
            _webElementImplementation.SendKeys(text);
        }
    
        public void Submit()
        {
            _webElementImplementation.Submit();
        }
    
        public void Click()
        {
            _webElementImplementation.Click();
        }
    
        public string GetAttribute(string attributeName)
        {
            return _webElementImplementation.GetAttribute(attributeName);
        }
    
        public string GetCssValue(string propertyName)
        {
            return _webElementImplementation.GetCssValue(propertyName);
        }
    
        public string TagName
        {
            get { return _webElementImplementation.TagName; }
        }
    
        public string Text
        {
            get { return _webElementImplementation.Text; }
        }
    
        public bool Enabled
        {
            get { return _webElementImplementation.Enabled; }
        }
    
        public bool Selected
        {
            get { return _webElementImplementation.Selected; }
        }
    
        public Point Location
        {
            get { return _webElementImplementation.Location; }
        }
    
        public Size Size
        {
            get { return _webElementImplementation.Size; }
        }
    
        public bool Displayed
        {
            get { return _webElementImplementation.Displayed; }
        }
    }
    
person Jacob Brewer    schedule 11.01.2017