2009-06-10 3 views
19

Сценарий. Язык C#, модульное тестирование с использованием VS2008 Рамка модульного тестированияСтатические классы UnitTesting

У меня есть статический класс со статическим конструктором и двумя методами. У меня есть 4 метода тестирования, написанных для тестирования всего класса. У моего Static Constructor есть несколько важных инициализаций.

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

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

ответ

11

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

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

0

Ну, вы не указали, какой язык вы использовали, но если есть способ открыть свой статический класс из тестового файла, то я бы добавил к нему поддельный деструктор, который вы можете вызвать после каждый тест. Таким образом, «деструктор» остается в тестовом классе и из вашего производственного кода.

0

Вы можете использовать Typemock's Isolator, который способен издеваться над статическими классами, поэтому в каждом тесте вы можете «определить», как будет работать статичность.

Это не бесплатный продукт.

0

Похоже, вы пытаетесь проверить статический конструктор. Это кажется плохой идеей.

Рассмотрите возможность извлечения логики инициализации в отдельный (нестатический) класс.

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

Тогда ваш производственный код может использовать MySingleton и игнорировать MyInitializer. С другой стороны, ваши тесты могут игнорировать MySingleton и весело создавать новый экземпляр MyInitializer для каждого теста, каждый раз получая новое начало.

1

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

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

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

5

Я хотел бы переместить инициализацию из статический конструктор к методу, вызываемому конструктором.Сделав этот метод внутренним, вы можете вызвать этот метод из своих тестов, чтобы повторно инициализировать класс.

public static class MyClass 
{ 
    public static MyClass() 
    { 
     initialize(); 
    } 

    internal static void initialize() 
    { 
     // Do initialization (and cleanup if necessary) 
    } 

    public static void Method1() {} 
    public static void Method2() {} 
} 

Для того, чтобы вызвать внутренние методы, которые нужно использовать атрибут InternalsVisibleTo, как описано в this blog.

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

Но, как сказал Эндрю Шеферд, вы также должны проверить, является ли статический класс лучшим дизайном этого класса.

34
Type staticType = typeof(StaticClassName); 
ConstructorInfo ci = staticType.TypeInitializer; 
object[] parameters = new object[0]; 
ci.Invoke(null, parameters); 

из http://colinmackay.scot/2007/06/16/unit-testing-a-static-class/

+21

эй взгляд, фактический ответ на вопрос, а не «не делай этого». – deltree

+0

Хорошо работает, однако мне пришлось вручную объявить статический пустой конструктор в классе (даже если он обычно не нужен). –

+1

Почему параметры, используемые для статического конструктора? Можем ли мы называть его 'ci.Invoke (null, null);'? – SerG

0

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

using System.Reflection; // or Mono.Reflection 

public static class MyClass{ 
    private static string myString; 
} 

var newValue = "Potatoes";    
var field = typeof(MyClass).GetField("myString", BindingFlags.Static | BindingFlags.NonPublic); 
field.SetValue(null, newValue); // the first null is because the class is static, the second is the new value