Заменить метод с параметрами замыканием в метаклассе

У меня есть два класса:

class Foo {
    String doSomething(String a, String b) {
        return 'Not Working'
    }
}


class Bar {
    String methodIWannaTest() {
        return new Foo().doSomething('val1', 'val2')
    }
}

И я хочу заменить 'doSomething' в тесте, но это не работает

class BarTests {
    @Test
    void testMethodIWannaTest() {
        Foo.metaClass.doSomething {String a, String b -> return 'Working'}

        assert new Bar().methodIWannaTest() == 'Working' //THIS TEST FAIL, return 'Not Working'
    }
}

*Я знаю, что тест на самом деле не имеет смысла, он просто показывает мою точку зрения

Что я делаю неправильно? Можно ли это сделать без использования mockFor?


person Thermech    schedule 23.05.2013    source источник
comment
Он работает как скрипт в Groovy 2.1.3 ... Может быть, что-то связано с junit?   -  person Will    schedule 23.05.2013
comment
Он также работает как модульный тест в Grails 2.2.0.   -  person dmahapatro    schedule 23.05.2013
comment
@Thermech Какую версию Grails вы используете?   -  person dmahapatro    schedule 23.05.2013
comment
Я использую Grails 2.2.2   -  person Thermech    schedule 23.05.2013


Ответы (4)


Я бы посоветовал вам начать тест заново. Baby Steps — это то, чему я следую. :)

  • Создайте новое приложение Grails.
  • Создайте Foo и Bar внутри src/groovy под пакетом.
  • Создайте модульный тестовый пример из командной строки. Поставьте нужный тестовый код.
  • Выполнить grails test-app

[Граилс v2.2.0]

person dmahapatro    schedule 23.05.2013

Другой альтернативой является использование Groovy MockFor.

def mock = MockFor(Foo)
mock.demand.doSomething = {String a, String b -> return 'Working'}
mock.use {
  assert new Bar().methodIWannaTest() == 'Working'
}

Недостатком является то, что была ошибка, из-за которой модульные тесты не очищали макет. Это исправлено для версии 2.2.3.

person Community    schedule 23.05.2013

Я нашел проблему:

Во-первых, в моем примере я забыл '=' при определении замыкания

Foo.metaClass.doSomething {String a, String b -> return 'Working'}

должно быть

Foo.metaClass.doSomething = {String a, String b -> return 'Working'}

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

person Thermech    schedule 28.05.2013

Я попробовал это на GGTS 3.2.0 и получил следующие результаты.

Скопировал весь код и запустил на Grails 2.2.2: все заработало корректно. Однако затем я закомментировал Foo.metaClass.doSomething = {String a, String b -> return 'Working'} строку и, на удивление, тест все равно прошел успешно. Я сделал больше изменений, и метакласс, казалось, просто «кэшировался» между тестами: изменения не имели никакого эффекта.

Затем я подумал, возможно ли, что Grails работает в интерактивном режиме. Перешел в раздел Настройки > Groovy > Grails > Запуск Grails и обнаружил, что установлен флажок "Оставлять внешний Grails запущенным". Во всплывающей подсказке даже есть такие слова: «Внимание: экспериментальная функция!». Снятие этого флажка помогло, и метакласс больше не кэшировался между тестовыми запусками. Мне все еще интересно, почему экспериментальная функция будет включена по умолчанию...

person medvaržtis    schedule 23.05.2013