Поблочное тестирование без утверждений

Следующий код, который вы написали, создает копию вашего списка во время его создания - поэтому он всегда пуст, независимо от того, что вы добавляете в список позже.

List<object> managedArray = new List<object>();
ArrayReferences.Add(typeof(T), managedArray);
return Array.AsReadOnly(managedArray.Select(s => (T)s).ToArray());

Вот как вы должны написать свой код, чтобы получить то, что вы хотите:

public static void Main()
{
    Derived d = new Derived();
    Console.WriteLine(d.AsReadOnly().Count);
    d.AddElement(new GenericObject { i = 2 });
    Console.WriteLine(d.AsReadOnly().Count);
}

public class Base<T>
{
    List<T> _items = new List<T>();

    public ReadOnlyCollection<T> AsReadOnly()
    {
        return Array.AsReadOnly(_items.ToArray());
    }

    public void AddElement(T obj)
    {
        _items.Add(obj);
    }

    public void RemoveElement(T obj)
    {
        _items.Remove(obj);
    }
}

public class Derived : Base<GenericObject>
{
}

public class GenericObject
{
    public int i = 0;
}

Что выводит:

0
1

Теперь стоит учесть, что List<T> уже есть метод AsReadOnly(), так что вы можете просто написать это:

public static void Main()
{
    var d = new List<GenericObject>();
    Console.WriteLine(d.AsReadOnly().Count);
    d.Add(new GenericObject { i = 2 });
    Console.WriteLine(d.AsReadOnly().Count);
}

public class GenericObject
{
    public int i = 0;
}

Это тоже работает.


Вот как вы должны сделать это, чтобы хранить более одного списка одновременно. Нет необходимости в наследовании.

public static void Main()
{
    Repository r = new Repository();
    Console.WriteLine(r.AsReadOnly<GenericObject>().Count);
    r.AddElement<GenericObject>(new GenericObject { i = 2 });
    Console.WriteLine(r.AsReadOnly<GenericObject>().Count);
}

public class Repository
{
    private Dictionary<Type, object> _references = new Dictionary<Type, object>();

    private void Ensure<T>()
    {
        if (!_references.ContainsKey(typeof(T)))
        {
            _references[typeof(T)] = new List<T>();
        }
    }

    public ReadOnlyCollection<T> AsReadOnly<T>()
    {
        this.Ensure<T>();
        return (_references[typeof(T)] as List<T>).AsReadOnly();
    }

    public void AddElement<T>(T obj)
    {
        this.Ensure<T>();
        (_references[typeof(T)] as List<T>).Add(obj);
    }

    public void RemoveElement<T>(T obj)
    {
        this.Ensure<T>();
        (_references[typeof(T)] as List<T>).Remove(obj);
    }
}

public class GenericObject
{
    public int i = 0;
}
26
задан lomaxx 26 September 2008 в 02:26
поделиться

14 ответов

Это было бы официальным способом сделать это:

// Act
Exception ex = Record.Exception(() => someCode());

// Assert
Assert.Null(ex);
17
ответ дан 28 November 2019 в 06:27
поделиться

Это - просто очень минимальный тест и должно быть зарегистрировано как таковое. Это только проверяет, что не взрывается, когда выполнено. Худшая часть о тестах как это - то, что они представляют ложное чувство безопасности. Ваше покрытие кода повысится, но это иллюзорно. Очень плохой аромат.

21
ответ дан 28 November 2019 в 06:27
поделиться

Если нет никакого утверждения, это не тест.

Выход, являющийся ленивым - может потребоваться немного времени, чтобы выяснить, как получить утверждение там, но определенно стоящий того, чтобы знать, что это сделало то, что Вы ожидали, что он сделает.

13
ответ дан 28 November 2019 в 06:27
поделиться

Они известны как испытания с помощью дыма и распространены. Они - основные проверки работоспособности. Но они не должны быть единственными видами тестов, которые Вы имеете. Вам все еще была бы нужна некоторая проверка в другом тесте.

6
ответ дан 28 November 2019 в 06:27
поделиться

Такие тестовые запахи. Это должно проверить, что файл был записан в, по крайней мере, что измененное время было обновлено, возможно.

я видел довольно много тестов, записанных этот путь, который закончил тем, что не тестировал ничего вообще, т.е. код не работал, но это не аварийно завершалось также.

, Если у Вас есть некоторое явное требование, чтобы код под тестом не выдавал исключение и Вы хотите явно вызвать этот факт (тесты как документы требований) тогда, я сделал бы что-то вроде этого:

try
{
  unitUnderTest.DoWork()
}
catch
{
  Assert.Fail("code should never throw exceptions but failed with ...")
}

..., но это все еще пахнет немного мне, вероятно, потому что это пытается доказать отрицание.

6
ответ дан 28 November 2019 в 06:27
поделиться

В некотором смысле вы делаете неявное утверждение - что код не вызывает исключение. Конечно, было бы ценнее взять файл и найти подходящую строку, но я полагаю, что что-то лучше, чем ничего.

2
ответ дан 28 November 2019 в 06:27
поделиться

В целом я вижу это появление в интеграционном тестировании, просто то, что что-то успешно выполнилось к завершению, достаточно хорошо. В этом случае я спокоен с этим.

я предполагаю, видел ли я его много раз в модульные тесты , мне было бы любопытно относительно того, насколько полезный тесты действительно были.

РЕДАКТИРОВАНИЕ: В примере, данном OP, существует некоторый тестируемый результат (результат файла журнала), таким образом предполагая, что, если никакая ошибка не была брошена, что это работало, лениво.

2
ответ дан 28 November 2019 в 06:27
поделиться

Это может быть хорошим прагматическим решением, особенно если альтернатива вообще не является тестом.

Проблема в том, что тест прошел бы, если бы все вызванные функции были неактивными. Но иногда просто невозможно убедиться, что побочные эффекты - это то, что вы ожидали. В идеальном мире было бы достаточно времени, чтобы выписать чеки для каждого теста ... но я там не живу.

Другое место, где я использовал этот шаблон, - это встраивание некоторых тестов производительности в модульные тесты, потому что это был простой способ запустить их при каждой сборке. Тесты ничего не утверждают, но измеряют, как долго тест проходил, и записывают это.

2
ответ дан 28 November 2019 в 06:27
поделиться

Я видел что-то вроде этого прежде, и я думаю, что это было сделано только для поддержания чисел покрытия кода. Это, вероятно, действительно не тестирует поведение кода. В любом случае я соглашаюсь, что это (намерение) должно быть зарегистрировано в тест для ясности.

1
ответ дан 28 November 2019 в 06:27
поделиться

Название теста должно документировать это.

void TestLogDoesNotThrowException(void) {
    log("blah blah");
}

Как тест проверяет, записывается ли журнал без подтверждения?

1
ответ дан 28 November 2019 в 06:27
поделиться

Я должен признать, что никогда не писал модульный тест, который проверил, что я регистрировался правильно. Но я действительно думал об этом и столкнулся с этим обсуждение из как это могло быть сделано с JUnit и Log4J. Не слишком симпатичный, но похоже, что это работало бы.

0
ответ дан 28 November 2019 в 06:27
поделиться

Тесты должны всегда что-то утверждать, иначе что вы доказываете и как вы можете последовательно воспроизводить доказательства того, что ваш код работает?

0
ответ дан 28 November 2019 в 06:27
поделиться

Мы делаем это все время. Мы дразним наши зависимости с помощью JMock, таким образом, я предполагаю в некотором смысле, что платформа JMock делает утверждение для нас..., но это проходит примерно так. У нас есть контроллер, который мы хотим протестировать:

Class Controller {
  private Validator validator;

  public void control(){
    validator.validate;
  }

  public setValidator(Validator validator){ this.validator = validator; }
}

Теперь, когда мы тестовый контроллер мы' не хотим тестировать Блок проверки допустимости, потому что это имеет свои собственные тесты. таким образом, у нас есть тест с JMock только, чтобы удостовериться, что мы звоним, проверьте:

public void testControlShouldCallValidate(){
  mockValidator.expects(once()).method("validate");
  controller.control;
}

И это - все, нет никакого "утверждения" для наблюдения, но когда Вы, управление вызовами и "проверить" метод не называют тогда платформой JMock, бросаете Вас исключение (что-то как "ожидаемый метод, не вызванный" или что-то).

у Нас есть те повсеместно. Это немного назад, так как Вы в основном устанавливаете свое утверждение, ТОГДА выполняют вызов к испытанному методу.

0
ответ дан 28 November 2019 в 06:27
поделиться

Я иногда использую свою предпочтительную платформу поблочного тестирования (NUnit) для создания методов, которые действуют как точки входа в определенные части моего кода. Эти методы полезны для профильной производительности, потребления памяти и потребления ресурсов подмножества кода.

Эти методы являются определенно не модульными тестами (даже при том, что они отмечены с [Тест] атрибут), и всегда отмечаются, чтобы быть проигнорированным и явно зарегистрированным, когда они проверяются в управление исходным кодом.

я также иногда использую эти методы в качестве точек входа для отладчика Visual Studio. Я использую Resharper для продвижения непосредственно в тест и затем в код, который я хочу отладить. Эти методы или не делают его до управления исходным кодом, или они получают свое очень собственное, утверждает.

Мои "реальные" модульные тесты создаются во время нормальных циклов TDD, и они всегда утверждают что-то, хотя не всегда непосредственно - иногда утверждения являются частью платформы насмешки, и иногда я в состоянии осуществить рефакторинг подобные утверждения в отдельный метод. Названия тех пересмотренных методов всегда запускаются с префикса, "Утверждают" для создания его очевидным для меня.

0
ответ дан 28 November 2019 в 06:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: