Moq не может создать фиктивный объект класса с параметром nullable в конструкторе - PullRequest
7 голосов
/ 17 июня 2011

У меня есть этот класс:

public class TestClass
{
 public TestClass(int? foo, string bar)
 {
   //..Something
 }
}

Я пытаюсь смоделировать это, используя MOQ, как это

var mockA = new Mock<A>(new object[] {(int?)1, string.Empty})

или это

var mockA = new Mock<A>(new object[] {1 as int?, string.Empty})

даже это

var mockA = new Mock<A>(new object[] {(int?)null, string.Empty})

Когда я пытаюсь получить объект, подобный этому

var objA = mockA.Object

выдает это исключение

Невозможно создать экземпляр прокси класса: TestClass. Не удалось найти конструктор, который соответствовал бы заданным аргументам: System.Int32, System.String

(для третьего выдается исключение нулевой ссылки)

Как заставить его распознавать, что первый аргумент имеет тип Nullable System.Int32, а не System.Int32.

(Пожалуйста, не обращайте внимания, что я издеваюсь над классом, а не над интерфейсом.)

Ответы [ 2 ]

8 голосов
/ 17 июня 2011

Чтобы смоделировать объект с помощью Moq, сам объект должен иметь пустой конструктор public. Методы, которые вы хотите смоделировать, должны быть virtual, чтобы их можно было переопределить.

Edit:

Я использую Moq v4.0.20926 (последний из NuGet) и выполняю следующую работу:

[TestMethod]
public void TestMethod1()
{
    var mock = new Mock<TestClass>(new object[] {null, null});
    mock.Setup(m => m.MockThis()).Returns("foo");

    Assert.AreEqual("foo", mock.Object.MockThis());
}

public class TestClass
{
    public TestClass(int? foo, string bar)
    {
    }

    public virtual string MockThis()
    {
        return "bar";
    }
}
4 голосов
/ 17 июня 2011

Причина этого заключается в том, что бокс с обнуляемым значением на самом деле не ограничивает значение Nullable<T>, он заключает в себе значение внутри.

В основном:

  1. Если вы укажете пустое значение, которое имеет значение, вы получите коробочную версию значения, поэтому коробочная версия (int?)1 будет такой же, как и коробочная версия 1
  2. Если вы укажете пустое значение, которое не имеет значения, вы получите нулевую ссылку, которая не имеет типа

Вы можете думать об операции бокса примерно так:

public static object Box(int? value)
{
    if (value.HasValue)
        return value.Value; // boxes the int value

    return null;            // has no type
}

Другими словами, ваш массив object[] вообще не получает копию значения Nullable, он просто получает копию значения int или null -ссылки, ни одна из которых не содержит Nullable<T> тип.

Вот код LINQPad для проверки:

void Main()
{
    int? i = 1;
    object o = i;

    o.Dump();
    o.GetType().Dump();

    i = null;
    o = i;
    o.Dump();
    o.GetType().Dump();
}

Выход:

1
System.Int32
1038 * нуль *
[NullReferenceException]

...