2009-08-03 5 views
3

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

Я хочу создать экземпляр mock SomeRelatedLibraryClass, который принимает в своем конструкторе макет экземпляра SomeLibraryClass. Как я могу высмеять SomeRelatedLibraryClass таким образом?

Код репо ...

Вот Основной метод, который я использую в моем тестовом консольном приложении.

public static void Main() 
{ 
    try 
    { 
     SomeLibraryClass slc = new SomeLibraryClass("direct to 3rd party"); 
     slc.WriteMessage("3rd party message"); 
     Console.WriteLine(); 

     MyClass mc = new MyClass("through myclass"); 
     mc.WriteMessage("myclass message"); 
     Console.WriteLine(); 

     Mock<MyClass> mockMc = new Mock<MyClass>("mock myclass"); 
     mockMc.Setup(i => i.WriteMessage(It.IsAny<string>())) 
      .Callback((string message) => Console.WriteLine(string.Concat("Mock SomeLibraryClass WriteMessage: ", message))); 

     mockMc.Object.WriteMessage("mock message"); 
     Console.WriteLine(); 
    } 
    catch (Exception e) 
    { 
     string error = string.Format("---\nThe following error occurred while executing the snippet:\n{0}\n---", e.ToString()); 
     Console.WriteLine(error); 
    } 
    finally 
    { 
     Console.Write("Press any key to continue..."); 
     Console.ReadKey(); 
    } 
} 

Вот это класс, который я использовал, чтобы обернуть один класс третьей стороны и позволяют ему быть Moq'd:

public class MyClass 
{ 
    private SomeLibraryClass _SLC; 

    public MyClass(string constructMsg) 
    { 
     _SLC = new SomeLibraryClass(constructMsg); 
    } 

    public virtual void WriteMessage(string message) 
    { 
     _SLC.WriteMessage(message); 
    } 
} 

Вот два примера 3 класса партии я работаю с (вы не можете редактировать ЭТИ):

public class SomeLibraryClass 
{ 
    public SomeLibraryClass(string constructMsg) 
    { 
     Console.WriteLine(string.Concat("SomeLibraryClass Constructor: ", constructMsg)); 
    } 

    public void WriteMessage(string message) 
    { 
     Console.WriteLine(string.Concat("SomeLibraryClass WriteMessage: ", message)); 
    } 
} 

public class SomeRelatedLibraryClass 
{ 
    public SomeRelatedLibraryClass(SomeLibraryClass slc) 
    { 
     //do nothing 
    } 

    public void WriteMessage(string message) 
    { 
     Console.WriteLine(string.Concat("SomeRelatedLibraryClass WriteMessage: ", message)); 
    } 
} 

ответ

2

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

10

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

public interface ISomeRelatedLibraryClassGateway { 
    void WriteMessage(string message); 
} 

Затем создать реализацию, маршруты всех обращений к классу третьего лица:

public class SomeRelatedLibraryClassGateway : ISomeRelatedLibraryClassGateway { 
    private readonly SomeRelatedLibraryClass srlc; 
    public SomeRelatedLibraryClassGateway(SomeRelatedLibraryClass srlc) { 
    this.srlc = srlc; 
    } 

    void ISomeRelatedLibraryClassGateway.WriteMessage(string message) { 
    srlc.WriteMessage(message); 
    } 
} 

Теперь классы в вашем приложении, которое будет зависеть от SomeRelatedLibraryClass теперь могут зависеть от ISomeRelatedLibraryClassGateway вместо этого, и этого интерфейса легко насмехаться. Класс SomeRelatedLibraryClassGateway не нуждается в модульных тестах; все, что он делает, это переходы. Это необходимо протестировать в функциональном тесте, но вы можете выполнить функциональное тестирование без издевок.

Надеюсь, это поможет.

+0

На самом деле проблема в том, что мне нужно высмеять SomeRelatedLibraryClass, который имеет параметр типа SomeLibraryClass. Я не понимаю, как шаблон Gateway позволяет мне более легко высмеивать этот класс. Я вообще использую шаблон Gateway при интеграции внешних зависимостей, но в этом примере я не учитывал определение интерфейса и реализацию, поскольку я не думаю, что это имеет отношение к проблеме. –

+1

Суть заключается в том, чтобы избежать издевательств SomeRelatedLibraryClass. Использование шаблона Gateway позволяет избежать издевательства над SomeRelatedLibraryClass, потому что (большинство из них) ваш код напрямую не зависит от него. Это пример кода рефакторинга, который легче тестировать. –

Смежные вопросы