2009-06-24 5 views
5

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

public ResultState getResultState(){ 
    ResultState resultState = new ResultState(); 
    // logic // 
    this.resultState = resultState; //set parent class field 
    return resultState; 
} 

ResultState - это объект, который не позволяет использовать многие его методы и поля. Я невежественный, как еще проверить такой метод, кроме:

assertNotNull(object.getResultState()) //the return ResultState is used by other class methods 

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

ответ

11

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

(Я не пытаюсь осветить проблему - иногда очень сложно сохранить герметичность, но эффективно проверить. Иногда стоит немного открыть объект, чтобы облегчить тестирование ...)

+0

+1 - примерно слово в слово, что я собирался сказать –

+0

Jon, Хороший вопрос - что важно для результата. Подумав об этом - самое главное, что результат должен быть объектом, ожидаемым методами, которые будут его использовать.И это выполняется в // LOGIC // разделе кода, где LOGIC манипулирует полями «this» Итак, я выполнил следующие тестовые сценарии: 1. Я настроил сеттеры и геттеры для этих полей 2. set 3) и построить его без исключений ... – 2009-06-24 16:01:56

5

Что делает этот объект? Если вы не можете запрашивать поля и т. Д., Я предполагаю, что он действует на какой-то объект, который вы передаете ему? Если это так, можете ли вы передать фиктивный объект, который реализует один и тот же интерфейс, но проверяет, что объект результата вызывает его с соответствующими аргументами, в ожидаемой последовательности и т. Д.?

например.

public class ResultObject { 
    public void actOn(ActedUpon obj) { 
     // does stuff 

где ActedUpon представляет собой интерфейс, и будет иметь «нормальную» внедрение и реализацию проверки (с помощью насмешливый рамки, как JMock здесь было бы идеально)

2

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

this.resultState = resultState;

в вашем геттере.

Сказанное, возвращающее resultState должно иметь некоторая цель, в противном случае почему вы возвращаете его? Поэтому проверьте, делает ли resultState то, что ему нужно.

0

Если то, что вы хотите, чтобы проверить это просто, что после вызова o.setResultState (resultState), вы можете получить resultState с o.getResultState(), тест будет что-то очень простое, как:

ResultState resultState = new ResultState(...); 
o.setResultState(resultState); 
assertEquals(resultState, o.getResultState()); 
2

Исходя из этого кода. Я бы сказал, что проверка на Not Null достаточно. Проверка функциональности возвращаемого ResultState принадлежит к испытаниям для ResultState. Вы пытаетесь проверить функциональность getResultState(). Единственное, что он делает, это создать новый объект и сохранить ссылку на него в this.resultState. Поэтому проверьте, не создал ли он его, и посмотрел, сохранил ли он ссылку.

2

Прискорбно, что вы используете getResultState(), чтобы создать объект ResultState, сам по себе, который на самом деле является вашим блокирующим устройством.Рассмотрим рефакторинг в следующем интерфейсе:

protected ResultState initResultState () 
{ 
    this.resultState = new ResultState(); 
    // Initialization Logic... 
    return this.resultState; 
} // END initResultState 

public ResultState getResultState () 
{ 
    if (this.resultState === null) 
    { 
     return this.initResultState(); 
    } 

    return this.resultState; 
} // END getResultState() 

С этой позиции легче проверить ваш метод получения. Определение класса потомка, который возвращает известный ResultState Stub для initResultState(), которые могут быть допрошены, а именно:

/** 
* The test fixutre's initResultState() method merely returns a simple Stub of 
* the ResultState object, which can be more easily interrogated. 
*/ 
public ResultState initResultState () 
{ 
    return new Stub_ResultState(); 
} // END initResultState 

Это по-прежнему оставляет вас с защищенным initResultState(), конечно. Рассмотрим следующий рефакторинга:

protected ResultState initResultState (ResultState newResultState) 
{ 
    this.resultState = newResultState; 
    // Initialization Logic... 
    return this.resultState; 
} // END initResultState 

public ResultState getResultState () 
{ 
    if (this.resultState === null) 
    { 
     return this.initResultState(new ResultState()); 
    } 

    return this.resultState; 
} // END getResultState 

Это позволяет вам переопределить метод getResultState() в потомке класса таким образом, что вы можете передать другой объект ResultState Заглушка манипулировать и допрошен после этого, например:

/** 
* The test fixture's getResultState() method always acts as a passthrough for 
* initResultState(), which is protected, so that the output of the protected 
* method can be interrogated. 
*/ 
public ResultState getResultState () 
{ 
    return this.initResultState(new Stub_ResultState()); 
} // END getResultState 

С этой позиции вам нужно два теста: тот, который переопределяет поведение initResultState() для проверки функциональности геттеров; другой, который переопределяет поведение getResultState(), чтобы проверить поведение initResultState(). Оба используют экземпляр класса Stub_ResultState, который обязательно является потомком класса ResultState, но обеспечивает открытый доступ к внутренним значениям его родительского объекта для опроса в модульных тестах.

Я надеюсь, что это имеет смысл, но не стесняйтесь просить разъяснений.

0

Выполняя новое в геттере, вы выполняете конкретную реализацию ResultState. В вашем текущем случае это означает непрозрачную реализацию своего состояния.

Представьте себе, что вместо того, чтобы обновить ResultState на месте, вы получили его с завода и что фабрика предоставила какой-то способ заменить макет ResultState, чтобы вы могли убедиться, что getResultState() с объектом ResultState между созданием и возвратом.

Простой способ получить этот эффект - это разбить создание ResultState на переопределяемый метод. Например,

public ResultState getResultState() { 
    ResultState resultState = createResultState(); 
    ... 

protected ResultState createResultState() { 
    return new ResultState(); 
} 

Тогда, предполагая, что ваш класс Test в том же пакете, вы можете создать подкласс в линии, который переопределяет getResultState() для возврата издеваться.

Хотя это работает, это хрупкий способ написать тесты.

Альтернативный подход заключается в голове к чему-то вроде

public ResultState getResultState() { 
    ResultState resultState = _resultStateFactory.newResultState(); 
    ... 

Это требует, чтобы вы выяснить, подходящий способ инжекции ResultStateFactory в объект, который является чем-то рамка инъекции зависимости велика для. Для тестов введите завод, который возвращает макет ResultState, который был загрунтован с соответствующими ожиданиями. Это уменьшает проблему тестирования до того, как «getResultState() правильно манипулирует объектом ResultState, прежде чем возвращать его?»

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