Мокинг метода groovy.sql.Sql.call (_, _, _)

Я пытаюсь издеваться над классом вызова groovy.sql.Sql (query, params [], closure). Ниже приведен метод в файле класса DatabaseService, на котором я пытаюсь это сделать.

public void getUsers(List<User> developerList, Sql sql) {
    sql.call("{? = call GETUSERS()}", [Sql.resultSet(OracleTypes.CURSOR)]) { result ->
        while (result.next()) {
            User user = new User()
            user .email = result.EMAIL
            user .lastName = result.LASTNAME
        }
    }
}

Мой макет действительно выполняет задачу, однако я не хочу, чтобы имитированное закрытие выполнялось. Я хочу издеваться над методом .call (,, _), чтобы пропустить только логику базы данных и вернуть список в закрытие в методе getUsers (). Я хочу, чтобы закрытие выполнялось в методе getUsers (), а не в макетном методе.

Ниже представлен макет, который я написал в SPOCK.

void "test getUsers(list,sql) some results"() {
    DataSource mockedSource = Mock(DataSource)
    Sql mockedSql = Mock(Sql)
    DatabaseService databaseService = new DatabaseService()
    databaseService.dataSource = mockedSource
    List<User> userList= new ArrayList<>();

    when:
    databaseService.getUsers(userList, mockedSql)

    then:
    1 * mockedSql.call(_, _, _) >> { return [[EMAIL: "A", LASTNAME: "B"]] }
    userList.size() == 1
}

Как и предполагалось, этот макет перезаписывает исходное закрытие метода, и мой список никогда не заполняется. Я, конечно, не хочу переписывать свой класс для использования Java, и я не могу изменить выполняемую хранимую процедуру.


person angryip    schedule 09.02.2016    source источник
comment
Почему бы просто не издеваться над методом службы, чтобы просто вернуть список   -  person tim_yates    schedule 09.02.2016
comment
потому что это не будет проверять, работает ли закрытие   -  person angryip    schedule 09.02.2016
comment
Хммм ... Я бы либо подделал источник данных, либо извлек замыкание, чтобы его можно было проверить   -  person tim_yates    schedule 09.02.2016


Ответы (1)


try :
int resultSetIdx = 0
def resutSet = Mock(ResultSet)
  ...
then:
  1 * mockedSql.call(_, _, _) >> { args -> args[2].call(resultSet) }
  2 * mockedResultset.next() >> { ++resultSetIdx > 1 ? false: true}
  1 * mockedResultset.getString("EMAIL") >> "A"

В методе getUsers () измените

user.lastName = result.LASTNAME
user.email = result.EMAIL

To

user.lastName = result.getString("LASTNAME")
user.email = result.getString("EMAIL")

Однако вы не должны имитировать Sql, а переписать уровень сервиса / dao, чтобы он был более тестируемым. протестируйте dao с помощью inmemory db, а сервисный уровень - с mocked dao.

person Jérémie B    schedule 09.02.2016
comment
исходный метод выдает исключение groovy.lang.MissingMethodException: сигнатура метода отсутствует: java.util.ArrayList.next () не применима для типов аргументов: () значения: [] Возможные решения: get (int), get (int), set (int, java.lang.Object), set (int, java.lang.Object), wait (), head () в вызове (result.next ()) {}) в методе getUsers - person angryip; 09.02.2016
comment
Хотя я понимаю, что могу переписать его, чтобы сделать его более тестируемым, я бы сделал вывод о насмешливых методах, но исключение замыканий не должно быть таким сложным. Кроме того, я бы предпочел повторно использовать уже созданные методы, чем писать все с нуля. :) Возможно, в Groovy есть альтернативный метод, который вернул бы набор результатов из подготовленного вызова, о котором я не знаю - person angryip; 09.02.2016
comment
это не о Groovy, а о насмешке над драйвером jdbc: это непросто и не очень полезно для теста - person Jérémie B; 09.02.2016
comment
Похоже, что массив, который мы создаем, мы делаем неправильно. groovy.lang.MissingPropertyException: нет такого свойства: EMAIL для класса: java.util.ArrayList $ Itr - person angryip; 09.02.2016
comment
Теперь вам нужно издеваться над ResultSet. вам действительно стоит посмотреть на различные db в памяти. вы можете создать соединение с двумя строками кода - person Jérémie B; 09.02.2016
comment
имитировать метод resultset .next () в предоставленном вами образце кода? - person angryip; 09.02.2016
comment
закрытие должно вызываться с Результатом. вам нужно настроить и предоставить имитацию ResultSet - person Jérémie B; 09.02.2016
comment
Позвольте нам продолжить это обсуждение в чате. - person angryip; 09.02.2016