2009-05-14 3 views
2

Я тестирую статический метод, который строит строку URL после проверки прокси и имен хостов и всех видов вещей. Этот метод использует внутренний флаг System.Net.Sockets.Socket.OSSupportsIPv6. Поскольку это статично, я не могу издеваться над этой зависимостью.Как выполнить единичный тест для конкретного поведения машины?

EDIT: (Это упростило много ... Я не могу изменить структуру метода с флагом, чтобы принять true/false).

На машинах разработки XP метод под вопросом возвращает прогнозируемый результат строки (в данном случае http://hostname/ ....). Наш сервер сборки, поддерживающий IPv6, возвращает совершенно другой результат (он дает мне что-то вроде http://192.168.0.1:80/....). Пожалуйста, не спрашивайте, почему - дело в том, что существуют два разных типа вывода, которые различаются в зависимости от операционной системы.

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

Какова наилучшая практика для написания теста в этом случае? Я помещаю оператор if в свой тест, который проверяет флаг, а затем ищет два разных выхода? Это, кажется, схематично мне, потому что

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

  2. Я в основном, соединяющего тест методы, потому что вы должны знать внутренности метода до устанавливают два случая.

Я устанавливаю два теста, по одному для каждой среды, которые просто проходят, если они находятся в неправильной среде? Я пишу какое-то сложное регулярное выражение, которое может выделить, какой результат он получил, и использовать больше, если/else логику, чтобы проверить его?

Любые предложения помогут!

ответ

1

Можете ли вы скрыть статический метод за абстрактным интерфейсом?

interface ISupportIPv6 
{ 
    bool supported { get; } 
} 

//class for unit testing 
class TestSupportsIPv6 : ISupportIPv6 
{ 
    public bool supported { get { return true; } } 
} 

//another class for more unit testing 
class TestDoesNotSupportIPv6 : ISupportIPv6 
{ 
    public bool supported { get { return false; } } 
} 

//class for real life (not unit testing) 
class OsSupportsIPv6 : ISupportIPv6 
{ 
    public bool supported { get { 
    return System.Net.Sockets.Socket.OSSupportsIPv6; } } 
} 
0

Я не понимаю, почему вы не можете издеваться над этим. Ваш метод должен принимать параметр bool SupportsIPv6, а в реальном коде вы передаете его System.Net.Sockets.Socket.OSSupportsIPv6. Затем вы проверяете свой метод, указав, что ваш параметр является истинным и ложным, и убедитесь, что он выплескивает правильные форматы как для истинных, так и для ложных случаев. Вуала, сделано.

+0

Ну, это значит, что сайты вызовов трудно проверить ... в основном он передает доллар. Это * может * не быть проблемой, по общему признанию ... –

+0

Это определенно было бы идеальным. Я на самом деле упростил его, есть несколько внешних вызовов, и флаг, на который он опирается, фактически находится в .dll. Я не контролирую. – womp

+0

Я вижу. Полагаю, что это позор. – mquander

0

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

Что сказал, определите, что означает «действительный»? Конечно, вы можете проверить его корректность: [0-9] {1,3} - это начало для регулярного выражения.

Вы можете проверить, что он доступен с помощью эхо-пакета ICMP (или ping (8)).

Если вы можете определить, что для вас означает «действительный», это должно определить единичный тест.

+0

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

2

Вы можете подделать звонок, представив посредника.Например:

public static class NetworkUtils 
{ 
    private static bool? forcedIPv6Support; 

    /// <summary> 
    /// Use this instead of Socket.OSSupportsIPv6 to 
    /// allow for testing on different operating systems. 
    /// </summary> 
    public static SupportsIPv6 
    { 
     get { return forcedIPv6Support ?? Socket.OSSupportsIPv6; } 
    } 

    /// <summary>Only use in testing!</summary> 
    public static void ForceIPv6Support(bool? value) 
    { 
     forcedIPv6Support = value; 
    } 
} 

Это не совсем приятно, но оно позволяет вам делать то, что вам нужно.

ChrisW's answer похоже, но с использованием интерфейса. Обычно я был бы поклонником интерфейса, но похоже, что он упрощает производственный код и конфигурацию. Мое решение, конечно, менее «чистое», но, возможно, более прагматичное. Я позволю вам судить :)

+0

Ваше решение короче, и поэтому (учитывая, что «сущности не должны умножаться за пределами необходимости») лучше. – ChrisW

+0

Оба являются прекрасными предложениями, которые я могу использовать, не слишком сильно удаляя код prod. – womp

1

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

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

например.

public interface IEnvironment 
{ 
    public bool SupportsIPV6 { get; } 
} 

И тогда ваш статический метод становится.

public static void DoSomething(IEnvironment environment) 
{ 
    if(environment.SupportsIPV6) 
    { 
     ... 
    } 
} 

Затем обеспечивает реализацию IEnvironment, которая требует от статического метода System.Net получить фактические условия для использования, но макет реализации для тестирования с известным значением.

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

E.g.

public Environment : IEnvironment 
{ 
    private static IEnvironment current = new Environment(); 
    public static IEnvironment Current 
    { 
    get { return current; } 
    set { current = value; } 
    } 

    public bool SupportsIPV6 
    { 
    return System.Net..... 
    } 
} 

Затем вызовите его из своего статического метода, используя.

public static void DoSomething(IEnvironemnt environment) 
{ 
    if(Environment.Current.SupportsIPV6) 
    { 
     ... 
    } 
} 

И вы можете изменить его в тестах с помощью

Environment.Current = new MockedEnvironment(); 

Хотя вы должны смотреть, если вы делаете какие-либо многопоточность с одноплодной подобное.

Смежные вопросы