#c# #entity-framework #mocking
Вопрос:
У меня есть функция, которая возвращает числовой динамический объект
public IEnumerable<dynamic> GetNameByRequestIds(List<long> requestIds) {
return (
from r in Session.All<Request>()
where requestIds.Contains(r.REQ_ID)
select new {
ReqId = r.REQ_ID,
Name = r.Name
}
).AsEnumerable();
}
В модульном тесте я издеваюсь над этим,
List<dynamic> myList = new List<dynamic>() {
new {
ReqId = 1,
Name = "myName",
}
};
_db.Setup(x => x.GetNameByRequestIds(It.IsAny<List<long>>())).Returns(myList);
Но когда я выполнил следующий код, он выдал исключение
Майкрософт.CSharp.привязка времени выполнения.Исключение RuntimeBinderException: «объект» не содержит определения для «ReqID»
var dynamicList = _db.GetNameByRequestIds(myReqIds).ToList();
foreach (var r in dynamicList ) {
Console.WriteLine(r.ReqId);
Console.WriteLine(r.Name);
}
Это работает, когда я запрашиваю реальную базу данных, но не проходит модульный тест.
В режиме отладки
- Динамический список, тип
System.Collections.Generic.List<dynamic> {System.Collections.Generic.List<object>}
и r показывает
- Тип
<Anonymous Type>
Ответ №1:
Какую насмешливую структуру вы используете? Это несколько похоже на Moq, однако код для доступа к высмеянным результатам выглядит неполным. Я попробовал вышеописанное с Moq (v16.4), и это сработало, как и ожидалось.
Что не ясно в вашем примере, так это тип для _db. Сокращенный пример того, что работает:
// The DB wrapper (i.e. you're real code to be mocked away)
public interface IData
{
IEnumerable<dynamic> GetNameByRequestIds(IEnumerable<long> ids);
}
public class Data : IData
{
public IEnumerable<dynamic> GetNameByRequestIds(IEnumerable<long> ids)
{
return (
from r in Session.All<Request>()
where requestIds.Contains(r.REQ_ID)
select new {
ReqId = r.REQ_ID,
Name = r.Name
}
).AsEnumerable();
}
}
// Then the code under test... (The service/controller you want to unit test...)
public class Consumer
{
private readonly IData _db;
public Consumer(IData db)
{
_db = db;
}
public void DoSomething(IEnumerable<long> ids)
{
foreach (var row in _db.GetNameByRequestIds(ids)
{
Console.WriteLine(row.ReqId);
Console.WriteLine(row.Name);
// Do whatever with the returned data rows...
}
}
}
// Then the Test setup itself...
[Test]
public void TestConsumerDoesSomething()
{
var mock = new Mock<IData>();
mock.Setup(x => x.GetNameByRequestIds(It.IsAny<IEnumerable<long>>())).Returns(populate());
var obj = new Consumer(mock.Object);
obj.DoSomething();
}
private IEnumerable<dynamic> populate()
{
return new List<dynamic>
{
new {ReqId = 1, Name = "myName"}
};
}
Все это, по-видимому, работало так, как и следовало ожидать, с тестируемым методом («doSomething»), получающим доступ к данным, предоставленным Макетом, вместо «реального» поставщика БД и издевательского динамического объекта, предоставляющего идентификатор и имя.
Комментарии:
1. Я тоже чувствую себя так странно, что позже игнорирую динамику и создаю объект. Это все равно работает.