#.net #unit-testing #c#-4.0 #rhino-mocks
#.net #модульное тестирование #c #-4.0 #rhino-mocks
Вопрос:
У меня есть следующий тестовый код:
parentViewModel = MockRepository.GenerateMock<IParentViewModel>();
parentViewModel.Expect(x => x.GetPropertyValue<IEnumerable<Milestone>>("JobMilestones")).Return(new Milestone[0]);
viewModel = new JobPenaltiesViewModel(j, new Penalty[0], _opContext, parentViewModel);
Assert.That(viewModel.Milestones.Count(), Is.EqualTo(0));
parentViewModel.VerifyAllExpectations();
List<string> propsChanged = new List<string>();
viewModel.PropertyChanged = (s, e) => propsChanged.Add(e.PropertyName);
parentViewModel.Raise(x => x.PropertyChanged = null, parentViewModel, new PropertyChangedEventArgs("JobMilestones"));
AssertPropertiesChangedAsExepected(propsChanged, 1, "Milestones");
Milestone m1 = GenerateMilestone(j);
List<Milestone> milestones1 = new List<Milestone> { m1 };
parentViewModel.Expect(x => x.GetPropertyValue<IEnumerable<Milestone>>("JobMilestones")).Return(milestones1).Repeat.Any();
IEnumerable<Milestone> milestones = viewModel.Milestones;
Assert.That(milestones.Count(), Is.EqualTo(1));
parentViewModel.VerifyAllExpectations();
Все тесты и утверждения выполняются успешно до тех пор, пока:
Assert.That(milestones.Count(), Is.EqualTo(1));
Вот где я получаю исключение:
Previous method 'IEnumerator.MoveNext();' requires a return value or an exception to throw.
Я перепробовал все, что мог придумать, и мое тестирование, похоже, показывает, что макет parentViewModel возвращает null или пустое перечисление (т. Е. Когда я использую отладчик для проверки возвращаемого значения, «Просмотр результатов» сообщает, что перечисление не вернуло результатов).
Чего мне здесь не хватает?
Комментарии:
1. Получите ли вы правильный результат, если попытаетесь выполнить:
IEnumerable<Milestone> milestones = parentViewModel.Milestones;
иAssert.That(milestones.Count(), Is.EqualTo(1))
? (Просто проверьте, где вы потеряли m1)2. Нет,
Assert.That(milestones.Count(), Is.EqualTo(1))
является источником исключения. Я никогда не добираюсь доparentViewModel.VerifyAllExpectations()
3. Хорошо, я не очень понял, что я имел в виду. Я имел в виду добавление строк сразу после,
parentViewModel.Expect(x => x.GetPropertyValue<IEnumerable<Milestone>>("JobMilestones")).Return(milestones1).Repeat.Any();
чтобы вы утверждали наparentViewModel
перед утверждением наviewModel
. Чтобы убедиться, что этоm1
находится вparentViewModel.JobMileStones
(я написал parentViewModel. Основные этапы в первом комментарии — моя ошибка.).4. Это дает мне:
This action is invalid when the mock object ... is in record state.
Я не уверен, почему он жалуется, что я в режиме записи, я использую синтаксис AAA. Нужно ли мне каким-то образом сбросить макет, прежде чем я попытаюсь вернуть второе значение?5. На самом деле сейчас я удалил этот раздел кода; после дальнейшего просмотра я понял, что он ничего не добавляет к моему тесту. Что я действительно хочу здесь протестировать, так это то, что когда родительский элемент уведомляет, что его коллекция «JobMilestones» изменилась, дочерний элемент уведомляет, что его коллекция «Milestones» изменилась. Тем не менее, я все еще хотел бы разобраться в этой проблеме, поэтому, если кто-нибудь сможет ответить на нее, я с радостью предоставлю ответ.
Ответ №1:
milestones.Count()
выполняется подобным образом (поскольку это объект IEnumerable):
- Установите счетчик в 0.
- Получить первый элемент.
- Добавьте 1 к счетчику.
- Перейти к следующему элементу.
- Шаг 3, пока следующий элемент не станет нулевым
- Возвращает счетчик
Поэтому я предлагаю вам немного переписать.
Вариант 1:
-
Создайте не коллекцию IEnumerable, а какой-нибудь более сильный объект, такой как
List
илиArray
:var milestones = viewModel.Milestones.ToArray();
//var milestones = viewModel.Milestones.ToList();После этого вы можете использовать соответственно
Count
иLength
свойство дляAssert
проверки:Assert.That(milestones.Count, Is.EqualTo(1));
//Assert.That(milestones.Length, Is.EqualTo(1)); -
Создайте локальную переменную для хранения параметра count:
var count = viewModel.Milestones.Count(); // .Count() method executes here.
Assert.That(count, Is.EqualTo(1));
Комментарии:
1. Я понимаю, что вы говорите, и в этом есть некоторый смысл. Но вопрос, который у меня все еще есть, заключается в том, что вызов
parentViewModel
должен возвращать реальныйList<>
объект (обратите внимание наExpect
вызов). Таким образом, вызовуCount()
даже не нужно перечислять его, он должен вызывать свойство Count в списке. Это почти так, как если бы RhinoMocks переписывал возвращаемое значение.2. @Coding Gorilla Я должен отметить, что вы вызываете
.Count()
методIEnumerable<Milestone>
, а неCount
свойствоList<Milestone>
, поэтому это приводит к перечислениюIEnumerable<Milestone>
.3. Это неверно, the . Метод Count() достаточно умен, чтобы выяснить, поддерживает ли тип underly свойство Count, и будет использовать это свойство, если оно доступно. Смотрите замечания здесь: msdn.microsoft.com/en-us/library/bb535181.aspx
4. Метод @Coding Gorilla В статье
.Count()
вызывается дляArray
объекта. В вашем случае вы вызываетеIEnumerable<Milestone>.Count()
, потому что вы выполнили приведение изList
вIenumerable
. Вы пробовали вызывать подобные методы:viewModel.Milestones.ToArray().Count()
?5. Базовым типом является a,
List<>
иCount()
метод пытается привести исходный код какICollection
, и если это успешно, он возвращаетCount
свойство (я декомпилировал метод, чтобы проверить это). Таким образом, на самом деле не должно быть необходимости перечислять коллекцию. Отладчик, однако, показал, что базовый тип является прокси-сервером, сгенерированным (по-видимому) RhinoMocks, я думаю, это та часть, которую я не понимаю.
Ответ №2:
С тех пор я удалил код-нарушитель; однако я так и не понял, почему он вел себя так, как было.