2008-09-25 3 views
1

У меня есть неизменяемый класс с некоторыми частными полями, которые задаются во время выполнения конструктора. Я хочу, чтобы модуль тестировал этот конструктор, но я не уверен, что это «лучшая практика» в этом случае.Как скомпилировать тестовые конструкторы классов неизменяемых классов?

Простой пример

Этот класс определен в Ассамблеи1:

public class Class2Test 
{ 
    private readonly string _StringProperty; 

    public Class2Test() 
    { 
     _StringProperty = ConfigurationManager.AppSettings["stringProperty"]; 
    } 
} 

Этот класс определен в Assembly2:

[TestClass] 
public class TestClass 
{ 
    [TestMethod] 
    public void Class2Test_Default_Constructor() 
    { 
     Class2Test x = new Class2Test(); 
     //what do I assert to validate that the field was set properly? 
    } 
} 

РЕДАКТИРОВАНИЕ 1: Я ответил на этот вопрос с потенциальным решением, но я не уверен, что это «правильный путь». Поэтому, если вы думаете, что у вас есть идея лучше, пожалуйста, опубликуйте ее.

Этот пример не стоит тестировать, но предположим, что у конструктора есть более сложная логика. Лучше всего избегать тестирования конструктора и просто предположить, что он работает, если все тесты для методов в классе работают?

EDIT 2: Похоже, я сделал образец немного простым. Я обновил его с более разумной ситуацией.

+0

Глядя на коде, я могу Не найди там заявление, которое может потерпеть неудачу. Я не вижу причин, почему его нужно протестировать. – jop 2008-09-25 00:18:17

+0

Я обновил образец. Предположим, что в конструкторе есть что-то, что может потерпеть неудачу, фактический код, который я пытаюсь проверить, довольно длинный, и я не хочу вставлять его здесь. – 2008-09-25 00:20:46

ответ

8

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

Если вы используете это поле в методе или что-то еще, вызовите этот метод и утвердите его.

Edit:

предположим, что конструктор имеет некоторые более сложную логику

Вы не должны выступать какой-либо логики в конструкторах.

Edit 2:

public Class2Test() 
{ 
    _StringProperty = ConfigurationManager.AppSettings["stringProperty"]; 
} 

Не делай этого! =) Ваш простой модульный тест теперь стал интеграционным тестом, потому что он зависит от успешной работы более чем одного класса. Напишите класс, который обрабатывает значения конфигурации. WebConfigSettingsReader может быть именем, и он должен инкапсулировать вызов ConfigurationManager.AppSettings.Передайте экземпляр этого класса SettingsReader в конструктор Class2Test. Затем, в вашем модульном тесте, вы можете высмеять свой WebConfigSettingsReader и отбросить ответ на любые вызовы, которые вы могли бы сделать с ним.

+0

+1 Вы хотите протестировать поведение, а не реализации. – 2008-09-25 00:20:17

1

Я правильно включил [InternalsVisibleTo] на Assembly1 (код), так что есть доверительные отношения с Assembly2 (тесты).

public class Class2Test 
{ 
    private readonly string _StringProperty; 
    internal string StringProperty { get { return _StringProperty; } } 

    public Class2Test(string stringProperty) 
    { 
     _StringProperty = stringProperty; 
    } 
} 

Что позволяет мне это утверждать:

Assert.AreEqual(x.StringProperty, "something"); 

Единственное, что я не очень люблю об этом заключается в том, что это не ясно (без комментариев), когда вы просто смотрите на Class2Test, что цель внутреннего имущества.

Дополнительные замечания были бы весьма полезными.

1

В вашем изменении у вас теперь есть зависимость от ConfigurationManager, которую трудно проверить.

Одно из предложений состоит в том, чтобы извлечь интерфейс для него, а затем заставить Class2Test ctor взять экземпляр IConfigManager в качестве параметра. Теперь вы можете использовать поддельный/фиктивный объект для настройки его состояния, таким образом, что любые методы, которые основаны на конфигурации могут быть проверены, чтобы увидеть, если они используют правильные значения ...

public interface IConfigManager 
    { 
     string FooSetting { get; set; } 
    } 

    public class Class2Test 
    { 
     private IConfigManager _config; 
     public Class2Test(IConfigManager configManager) 
     { 
      _config = configManager; 
     } 

     public void methodToTest() 
     { 
      //do something important with ConfigManager.FooSetting 
      var important = _config.FooSetting; 
      return important; 
     } 
    } 

    [TestClass] 
    public class When_doing_something_important 
    { 
     [TestMethod] 
     public void Should_use_configuration_values() 
     { 
      IConfigManager fake = new FakeConfigurationManager(); 
      //setup state 
      fake.FooSetting = "foo"; 
      var sut = new Class2Test(fake); 
      Assert.AreEqual("foo", sut.methodToTest()); 
     } 
    } 
Смежные вопросы