Как издеваться над частным внутренним классом

У меня есть приложение Spring, и я хочу создать унитарный тест на таком контроллере. Проблема в том, что класс Wrapper является закрытым внутренним классом, поэтому в тесте Wrapper не понимается. Можно ли издеваться над ним с помощью Mockito, не меняя класс контроллера. Я могу использовать prepareData() для получения экземпляра объекта, но я не знаю, можно ли это использовать для имитации этого объекта.

Спасибо

@Controller
public class Controller {

    private class Wrapper {
        private Object1 field1;
        private Object2 field2;
        private Object1 method1(){
           ...
        }
        private Object2 method1(){
           ...
        }
    }

    @ModelAttribute("data")
    public Wrapper prepareData() {
            return new Wrapper ();
}

    public String save(@ModelAttribute("data") Wrapper wrapper, BindingResult result, Model model){
        ...
    }
}

Итак, в моем тесте у меня было бы что-то вроде этого

@Test
public void usernameEmpty(){

    BindingResult result = Mockito.mock(BindingResult.class);
    Model model = Mockito.mock(Model.class);
    Wrapper data = //how to mock it
    when(data.method1()).then(new Foo1());
    when(data.method2()).then(new Foo2());
    String returned = controller.save(data, result, model);
    ....
}

person Javi    schedule 08.04.2011    source источник
comment
Мой я спрашиваю, почему вы хотите это сделать? Скорее всего, вы в конечном итоге протестируете неправильный код. Если у внутреннего класса есть зависимости (вероятно, полученные через контроллер?), смоделируйте их. Ждать? Ваш код компилируется? Если Wrapper является частным классом, можете ли вы использовать его в качестве аргумента для общедоступного метода?   -  person R. Martinho Fernandes    schedule 08.04.2011
comment
@Martinho Fernandes Я новичок в тестировании. Я просто хотел проверить метод сохранения, поэтому мне нужно было смоделировать объект Wrapper, чтобы я мог определить возвращаемые объекты, когда для него вызываются некоторые методы. Да, контроллер компилируется (тест не компилируется, но проблема в том, что я не могу использовать класс Wrapper в тесте). Может быть, есть лучший способ сделать это.   -  person Javi    schedule 08.04.2011
comment
Java просто снова удивил меня (отрицательно). Это делает меня бессильным помочь без компилятора Java под рукой :( В любом случае, даже если это разрешено, я не думаю, что это хороший дизайн, чтобы иметь общедоступный метод, который требует знания приватных. Это нарушает инкапсуляцию. Как вы собираетесь использовать этот метод в реальном реальном коде?Это возможно?   -  person R. Martinho Fernandes    schedule 08.04.2011
comment
@Martinho Fernandes, ты прав, я думаю, я изменю это на публичный   -  person Javi    schedule 08.04.2011


Ответы (1)


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

Может быть, вы думаете: но тогда... нужно тестировать много кода (очень большая неделимая вещь), нельзя ли протестировать что-нибудь поменьше? Ну да. Разработка через тестирование предписывает сделать минимальную реализацию и добавить больше кода, только если вы добавите больше тестов. Таким образом, вы начинаете с некоторого теста и минимальной реализации и развиваете их оба, пока тесты не будут иметь всю спецификацию, а код — всю реализацию.

Так что не беспокойтесь о частных внутренних классах. Проверьте свой классовый контракт!

person helios    schedule 08.04.2011
comment
И удачи в модульном тестировании! Это дает большую уверенность и возможность измениться без (непреднамеренной) поломки! - person helios; 08.04.2011
comment
Это не очень хорошо - это будет интеграционный тест. Вы нарушили один из основных принципов разработки через тестирование — тест должен быть простым! - person user710818; 14.12.2011
comment
Да. Но TDD — это методология разработки: сначала пишешь тест, потом пишешь код. В этом случае OP может получить другой дизайн (более простой и модульный) и не получить частный внутренний класс. В этой ситуации это только тестирование уже существующего кода. Сказал, что: я согласен, что это не простой тест, но частный внутренний класс не извлекается из класса контейнера, поэтому, хотя это не просто, это не интеграционный тест ИМХО (в любом случае, важная часть - это тест :) - person helios; 15.12.2011
comment
Я так не думаю. Пример: если файл обрабатывает некоторую информацию, иногда требуется внутренний кеш, обычно это можно сделать как частный внутренний класс. - person user710818; 15.12.2011