Re[3]: Тест метода класса Java, вызывающего другие методы
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 17.02.11 09:11
Оценка:
Здравствуйте, djandy_spb, Вы писали:

_>Реальный код выложить не могу, но например сначала класс вот такой:


_>
_>public class Statistics {
_>


_>не хочется его тестить типа генерируя разные стримы а потом сравнивая результат с заготовленными результатами.


Вообще то нужно полностью покрыть входы и выходы.

В твоем случае нужно разорвать зависимости от StreamReader и ResultFormatter

_>В этом примере отдельно можно оттестить StreamReader, ResultFormatter, можно логику обработки этих data1-data3 вынести в отдельный метод:

_>
_>}
_>


_>Теперь все замечательно тестируется кроме метода do — как убедиться что он правильно вызвал doInternal?


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

см. ниже как бы я орагнизовал этот класс для тестирования. Пример у тебя не самый удачный, т.к. не ясно, зачем тестировать StreamReader, а логику ты явно накидал прямо в браузере.
Итого, код с предположением, что StreamReader это какой то твой класс а не системный, что нужно изолироваться от ResultFormatter и тд
Очевидно, если StreamReader это системный, а ResultFormatter уже изолирован, то сгодится и твой первоначальный код

Как создавать такой класс для тестирования ? Очевидно — делать мок для Statistics, например Moq и всех его депенденсов или же наколбасить мок вручную, как показано ниже


// класс для тестирования. Создается или руками или через Moq
public class StatisticsMoq : Statistics {
    public Func<Stream, StreamReader> FuncReaderFrom {get; set;}
    public Func<ResultFormatter> FuncFormatter {get; set;}
    public Func<ResultFormatter, Func<Data,bool, string> > FuncGetFormat {get; set;}

    protected override StreamReader ReaderFrom(Stream stream)
    {
    return FuncReaderFrom();
    }
    
    protected override ResultFormatter Formatter()
    {
    return FuncFormatter();
    }
    
    protected override Func<Data,bool, string> getFormat(ResultFormatter formatter)
    {
         return FuncGetFormat(formatter);
    }
}

public class Statistics {
    public String do(Stream stream) {
        // логика полностью тестируема со всеми потрохами    
         
        reader = ReaderFrom(stream);
        formatter = Formatter();

    var dataSequence = FetchFrom(reader);

        return FormatSequence(dataSequence, getFormat(formatter) );        
    }
    
    protected virtual Func<Data,bool, string> getFormat(ResultFormatter formatter)
    {
         // при тестировании можно(если нужно) что бы распознавать бехевиор FormatSequence 
  
         return (data, valid, stream) => formatter.format(valid.ToValidEnum();
    }

    protected virtual StreamReader ReaderFrom(Stream stream)
    {
        // этот метод можно(если нужно) переопределить для тестирования и там возвращать мок-ридер, что бы изолировать тесты от стрима      
         
    return new StreamReader(stream);
    }
    
    protected virtual ResultFormatter Formatter()
    {
        // этот метод можно(если нужно) переопределить для тестирования и там возвращать мок-форматтер, 
        // например если формат слишком сложный что бы колбасить его в тестах

    return new ResultFormatter();
    }
    
    public static IEnumerable<Data> FetchFrom(StreamReader reader)
    {  // идея в том, что извлечение из стрима отделяется от остальной логики. метод тестируемый - зависимость только от ридера  
        yield return reader.ReadData();
        yield return reader.ReadData();
        yield return reader.ReadData();
    }
    
    public static FormatSequence(IEnumerable<Data> seq, Func<Data,bool,string> format) 
    {
        // основная логика полностью тестируема - депенденсы только от Data
        
    var data1 = seq.ElementAt(1);
    var data2 = seq.ElementAt(2);
    var data3 = seq.ElementAt(3);
        
    if (data1.valid())
            return format(data1, true);
        if (data2.valid()) 
            return format(data1, false) + format(data2,true);
        if (data3.valid())
            return format(data1, false) + format(data2, false) + format(data3,true);
            
        что вернуть если valid ни разу не встретилось ?
    }
}

public enum ValidEnum
{
  VALID,
  INVALID
}

public static Helper
{
   public static ValidEnum ToValidEnum(this bool isValid)
   {
        return isValid ? VALID : INVALID;
   }
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.