У нас есть много тестов с использованием Class.ReceivedCalls () и var tmp = Class.Received (int) .Property; чтобы проверить количество звонков. В версии 3 AutoFixture он правильно сообщал количество вызовов, особенно свойств, чего он больше не делает. Счетчик вызовов методов, кажется, все еще в порядке.
Учитывая, что у нас есть следующий код:
public interface IRunSpeed
{
int Speed { get; }
}
public class GetToDaChoppa
{
private readonly IRunSpeed _runSpeed;
public GetToDaChoppa(IRunSpeed runSpeed)
{
_runSpeed = runSpeed ?? throw new ArgumentNullException(nameof(runSpeed));
}
public void DoItNow()
{
var runningSpeed = _runSpeed.Speed;
}
}
И учитывая, что у нас есть следующие тесты:
[Fact]
public void DoItNow_WithOutAutoNSubstitute()
{
// Arrange
var runSpeed = Substitute.For<IRunSpeed>();
runSpeed.Speed.Returns(2);
var sut = new GetToDaChoppa(runSpeed);
//Act
sut.DoItNow();
//Assert
var tmp = runSpeed.Received(1).Speed;
Assert.Single(runSpeed.ReceivedCalls());
}
[Theory, AutoNSubstituteData]
public void DoItNow_UsingAutoNSubstitute(
[Frozen] IRunSpeed runSpeed,
GetToDaChoppa sut)
{
// Arrange
runSpeed.Speed.Returns(49);
//Act
sut.DoItNow();
//Assert
var tmp = runSpeed.Received(1).Speed;
Assert.Single(runSpeed.ReceivedCalls());
Мой AutoNSubstituteDataAttribute выглядит так:
public class AutoNSubstituteDataAttribute : AutoDataAttribute
{
public AutoNSubstituteDataAttribute()
: base(() => new Fixture()
.Customize(new AutoNSubstituteCustomization()))
{
}
}
Первый тест «DoItNow_WithOutAutoNSubstitute» работает нормально. Но второй тест «DoItNow_UsingAutoNSubstitute» возвращает 2 для «ios.Received (1) .Speed;».
Он также возвращает 2 для runSpeed.ReceivedCalls ();.
Из-за этого мы в настоящее время не можем обновить наши Решения до версии 4, так как у нас сразу появляется> 1000 неудачных тестов на одно решение. Есть какие-нибудь указания относительно того, в чем может быть проблема или где искать исправление?
Спасибо, что подняли вопрос. На самом деле, эта проблема не имеет ничего общего с AutoFixture, хотя и нас она тоже затрагивает 😕
Эта проблема в основном вызвана xUnit, и если вы перепишете тест следующим образом, он пройдет:
`` С #
[Теория, AutoNSubstituteData]
public void DoItNow_UsingAutoNSubstitute_CreateManually (прибор IFixture)
{
// Договариваться
var runSpeed = fixture.Freeze
var sut = fixture.Create
runSpeed.Speed.Returns (49);
//Act
sut.DoItNow();
//Assert
var tmp = runSpeed.Received(1).Speed;
Assert.Single(runSpeed.ReceivedCalls());
}
`` ''
Когда вы запускаете тесты, xUnit пытается отформатировать имя теста за вас. Если он обнаруживает, что этот тип неизвестен и не имеет перегрузки ToString()
, он использует структурную проверку и рекурсивно выбирает значения свойств. Если вы проверите название теста, вы увидите следующее:
Как вы могли заметить, xUnit получил значение свойства Speed
чтобы красиво показать вам тестовый аргумент. Поскольку это обычный вызов, NSubstitute посчитал это вызовом.
Довольно странно, что у вас не было этой проблемы с v3, поскольку в этом отношении ничего не изменилось. Я только что протестировал xUnit2 + AutoFixture v3
но проблема не исчезла. Возможно, вы тоже обновили xUnit.
Что касается обходного пути, у меня есть хорошие и плохие новости. Хорошей новостью является то, что эта проблема будет решена в следующей основной версии NSubsitute, поскольку он начал переопределять метод ToString()
для возврата идентификатора прокси. В результате xUnit больше не трогает свойства:
Плохая новость в том, что NSubsitute v4 еще не выпущен.
Я мог бы предложить вам либо:
master
исходный код NSubsitute, создайте локальную сборку и используйте свой собственный NSubsitute.dll
вместо пакета NuGet. После выпуска версии 4 вы можете переключиться на пакет NuGet.Приносим извинения за неудобства, но, к сожалению, мы ничего не можем сделать на стороне AutoFixture, чтобы исправить эту проблему.
только что проверил это. наконец, наши тесты, подтверждающие ReceivedCalls, снова дали успешный результат.
Что-то, что все еще терпит неудачу, - это утверждения на Received (x), такие как Received (1) .Speed Daniel, упомянутый выше.
У вас тоже есть ответ / решение для шапки?
Вы работаете над одним проектом? :) Если да, не могли бы вы пояснить, как вы устранили проблему?
Предложенные выше варианты должны помочь в решении обеих проблем. Если нет - проясните сценарий.
не совсем тот же проект, но в той же компании.
мы были на xunit 1.9 + nsubstitute 2/3 в течение долгого времени и, наконец, смогли получить наши внутренние сборки (пакеты nuget, поэтому простой способ вернуться к более старой версии только одной ссылки не так прост, как кажется быть), чтобы быть совместимым с xunit2. и теперь у нас есть эти две проблемы.
Мы уже опробовали некоторые вещи и, наконец, подумали, что это должно иметь какое-то отношение к автофиксации - из-за замороженного атрибута и жестко запрограммированного счетчика выполнения тестов - или чего-то в этом роде.
После того, как Дэниел открыл это дело, он отправил мне ссылку на него.
так же, как вы описали выше, я заменил ссылку на nuget 3.1 ссылкой из недавно скомпилированного проекта nsubstitute. после этого у меня теперь 118 вместо 178 неудачных тестов, потому что Receiced (x) по-прежнему оценивает неправильное количество вызовов.
мой проект в настоящее время основан на .net 4.5.2 с указанием xunit2, текущей версии репо nsubstitute и autofixture 4.2. все тесты терпят неудачу по одним и тем же двум причинам - также есть некоторые полученные вызовы, которые не проходят в модульных тестах.
Думаю, мне нужно еще раз взглянуть на это глубже, когда я снова вернусь в офис (на пасху).
может быть, @dklinger тем временем может описать сценарий.
@dklinger @evilbaschdi Пожалуйста, свяжитесь с нами после того, как у вас будет возможность проверить это - довольно интересно, почему вы все еще видите проблемы, даже после того, как вы применили патч.
Повторно откройте проблему, чтобы указать, что расследование еще продолжается.
Итак, я проверил последние несколько часов. Во-первых: спасибо за ваш ответ, ваши объяснения и предложения - это очень помогло.
Я тестировал v4 NSubstitute. Это работает для моего примера кода выше, но не решает полностью проблему в наших реальных проектах. Проблема в том, что он решает проблему неправильного счетчика ReceivedCalls только для вызовов SUT к методам, а не к свойствам.
Пример нашего теперь рабочего кода:
[Theory, AutoNSubstituteData]
public void DoItNow_UsingAutoNSubstitute(
[Frozen] IRunSpeed runSpeed,
GetToDaChoppa sut)
{
// Arrange
runSpeed.Speed.Returns(49);
//Act
sut.DoItNow();
//Assert
var tmp = runSpeed.Received(1).Speed;
Assert.Equal(1, runSpeed.ReceivedCalls().Count());
}
Но если я изменю метод "GetToDaChoppa.DoItNow ();" чтобы быть свойством "GetToDaChoppa.DoItNow", ReceivedCallsCount снова равен +1:
[Theory, AutoNSubstituteData]
public void DoItNow_UsingAutoNSubstitute(
[Frozen] IRunSpeed runSpeed,
GetToDaChoppa sut)
{
// Arrange
runSpeed.Speed.Returns(49);
//Act
var x = sut.DoItNow;
//Assert
var tmp = runSpeed.Received(1).Speed;
Assert.Equal(1, runSpeed.ReceivedCalls().Count());
}
Я думаю, что это снова связано с именованием xUnit, поскольку мы получаем это для реализации рабочего метода:
И этот для нерабочей реализации свойства:
Похоже, что xUnit вызывает SUT-свойство, чтобы получить его значение, чтобы использовать его для имени теста, но не делает этого для SUT-методов. Моя первая мысль заключалась в том, что это связано с возвращаемым значением нашего метода GetToDaChoppa (), которое было недействительным. Но даже после изменения его на «public int GetToDaChoppa ()» xUnit по-прежнему не вызывает его для получения возвращаемого значения для имени теста. Проблема только в использовании свойств.
А пока я снова застрял. Я полностью согласен с тем, что это не проблема AutoFixture. Но, по вашему мнению, зная все пакеты лучше, чем мы, что бы вы посоветовали?
@dklinger Спасибо за продолжение! Не могли бы вы поделиться MCVE кода для последнего сценария, который все еще терпит неудачу? Просто чтобы убедиться, что ничего не упущено, и я не неправильно понял условия.
После этого я попытаюсь разобраться, почему это происходит и как с этим справиться.
Спасибо.
Ага, конечно. Вот:
Тестируемая система:
public interface IRunSpeed
{
int Speed { get; }
void Dude();
int Dude2();
}
public class GetToDaChoppa
{
private readonly IRunSpeed _runSpeed;
public GetToDaChoppa(IRunSpeed runSpeed)
{
_runSpeed = runSpeed ?? throw new ArgumentNullException(nameof(runSpeed));
}
public int DoItNow
{
get
{
var runningSpeed = _runSpeed.Speed;
return 0;
}
}
}
Прецедент:
[Theory, AutoNSubstituteData]
public void DoItNowAsProperty_UsingAutoNSubstitute(
[Frozen] IRunSpeed runSpeed,
GetToDaChoppa sut)
{
// Arrange
runSpeed.Speed.Returns(49);
//Act
var x = sut.DoItNow;
//Assert
var tmp = runSpeed.Received(1).Speed;
Assert.Equal(1, runSpeed.ReceivedCalls().Count());
}
В настоящее время я пытаюсь следить за обсуждениями на https://github.com/xunit/xunit/issues/1386 и https://github.com/AutoFixture/AutoFixture/issues/805. Возможно, мы что-то делаем не так или есть способ запретить xUnit автоматически генерировать имя теста.
Я также попытался создать свой собственный атрибут TheoryAttribute, переопределяющий свойство DisplayName, но это тоже не помогает, поскольку xUnit каким-то образом все еще использует автоматически сгенерированное имя внутри. Но это просто fyi и совершенно не связано с демонстрационным кодом выше.
public sealed class MyTheoryAttribute : TheoryAttribute
{
public MyTheoryAttribute([CallerMemberName] string memberName = null)
{
DisplayName = "MyTestCase";
}
}
Привет, снова я :)
Это действительно xUnit2, вызывающий все свойства и поля параметров тестового метода, которые имеют сложный тип. Строка кода следующая: https://github.com/xunit/assert.xunit/blob/2b70a9b0c5bb291f98472ec24cec437acf8d65c8/Sdk/ArgumentFormatter.cs#L156
Спасибо за поддержку. Я повторно открыл проблему в xUnit-Repo, обсуждение которой должно продолжаться: https://github.com/xunit/xunit/issues/1682
@dklinger Спасибо за подробный сценарий. Это действительно довольно сложно и сложно как-то обойтись. С точки зрения AutoFixture и NSubsitute нет разницы, вызывается ли код где-то глубоко внутри xUnit или в теле теста.
Обычно в качестве обходного пути можно использовать четкую функцию NSubstitute:
runSpeed.ClearReceivedCalls();
Этот код следует запускать в прологе каждого теста, где вы проверяете точное количество вызовов. Он отлично работает, если у вас есть несколько тестов, однако очевидно, что если затронуты тысячи тестов, это не сильно поможет 😅
Жаль, что интеграция NSubsitute + xUnit2 + AutoFixture не работает должным образом и страдает от подобных проблем. Продукт AutoFixture был разработан, чтобы упростить жизнь, а не превратить ее в кошмар 😕 Надеюсь, ребята из xUnit посоветуют вам быстрый способ решения проблемы для всего проекта.
Дайте мне знать, если вы считаете, что мы можем что-то сделать с нашей стороны, чтобы улучшить ситуацию.