2012-04-05 2 views
2

У меня есть проект Visual Studio 2008 C# .NET 3.5, для которого я выполняю модульные тесты, но я столкнулся с проблемой. Мой код ссылается на стороннюю сборку, которая реализует объекты с внутренними конструкторами.модульное тестирование с объектами от сторонних сборок

Например:

// in 3rd party assembly 
public class Bar 
{ 
    // internal constructor 
    internal Bar(); 
    public int Id { get; } 
    public string Name { get; } 
    public Foo Foo { get; } 
} 

public class Foo 
{ 
    // internal constructor 
    internal Foo(); 
    public Collection<Bar> GetBars(); 
} 

Один метод мой, что я хотел бы модульное тестирование заключается в следующем:

// in my assembly 
public static Bar FindByName(this Collection<Foo> c, string name) 
{ 
    // search through the Foos to find the first bar with the matching name 
} 

И проверить это следующим образом:

void TestMethod() 
{ 
    Collection<Foo> foo_pool = new Collection<Foo>() 
    { 
     new Foo() { /*..*/ } // Error! ctor is inaccessible 
    }; 

    Bar b = foo_pool.FindByName("some_name"); 
    assert_equal (b.Name, "some_name"); 
} 

Но, Я не могу создавать объекты типа Foo или типа Bar. Итак, как я могу тестировать свой метод?

Благодаря

+1

Уверены ли вы, что есть внутренние конструкторы? То, как вы написали 'Foo' и' Bar', отображает * неявные * конструкторы. Если вы специально не используете 'internal Foo() {}', то компилятор будет генерировать конструктор без параметров с той же видимостью, что и класс. –

+0

Да, я уверен. Браузер объектов показывает их как внутренние. Я обновил код, чтобы сделать это явным. – PaulH

ответ

3

Для модульных тестов, вы можете использовать класс PrivateObject (имена Microsoft.VisualStudio.TestTools.UnitTesting) для создания объектов с частными застройщиками и даже проверить личные методы.

http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.privateobject(v=vs.90).aspx

http://www.gangleri.net/2007/11/15/PrivateObjects.aspx

Вот пример:

[TestMethod] 
public void TestMethod2() 
{ 
    // Arrange 
    var po = new PrivateObject(typeof(MyObject)); 
    var obj = (MyObject)po.Target; 
    // Act 
    var result = obj.Calculate(2); 
    // Assert 
    Assert.AreEqual(3, resul); 
} 

public class MyObject 
{ 
    internal MyObject() 
    { 

    } 

    public int Calculate(int a) 
    { 
     return 1 + a; 
    } 
} 

Он использует отражение точно так же, как предложение Джима, но PrivateObject класс инкапсулирует всю работу, чтобы создать экземпляр с частными застройщиками ,

+0

Это очень аккуратно, но я получаю сообщение 'Can not convert type PrivateObject to Foo', когда я пытаюсь использовать между ними. – PaulH

+0

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

+1

Вы пытаетесь применить экземпляр PrivateObject к объекту Foo или «Target» экземпляра PrivateObject для Foo? – Fabio

1

Вы можете использовать отражение для создания объектов с непубличными конструкторами. См. this question on SO.

Вот решение Ани из приведенной выше ссылке:

BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Instance; 
CultureInfo culture = null; // use InvariantCulture or other if you prefer 
object instantiatedType = 
    Activator.CreateInstance(typeToInstantiate, flags, null, parameter, culture); 

Activator.CreateInstance будет найти правильный конструктор на основе параметров, вы даете ему.

0

Если классы arent запечатаны/notinheritable, то вы можете вывести «издеваемый» класс из целевого целевого класса и добавить свой собственный конструктор. Пока вы меняете базовые методы, которые вы тестируете, это должно работать.

Например:

public class MyBar:Bar 
{ 
    // internal constructor 
    public MyBar(object throwaway) 
    { 
     //call base constructor if necessary 
    }; 
    public int Id { get; } 
    public string Name { get; } 
    public Foo Foo { get; } 
} 
+0

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

+0

Не уверен, что я вижу, что это не решает вашу проблему. Вы можете извлечь из этого. Вы не можете вызвать внутренний конструктор, но ваш макет может выполнять одно и то же поведение (копировать/вставлять из отражателя или ildasm). Если это не достаточно хорошо, тогда вы должны рассматривать другой шаблон для построения объекта, который не так сильно зависит от конкреций. – StingyJack

+1

Кроме того, у этого есть информация http: //www.rvenables.com/2009/08/instantiation-classes-with-internal-constructors/ – StingyJack

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