Как я могу проверить эти методы ввода-вывода с помощью Mock ()? Использование groovy & spock - PullRequest
0 голосов
/ 26 июня 2019

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

У меня есть два метода, которые я хочу проверить. И я хотел бы протестировать второй с помощью Mock, но не могу понять, что делать.

Вот первый метод:

String readFileContents(Path filePath) {
        StringBuilder fileContents = new StringBuilder()
        BufferedReader br = Files.newBufferedReader(filePath, StandardCharsets.UTF_8)
        String line
        while ((line = br.readLine()) != null) {
            fileContents.append(line).append('\n')
        }
        fileContents
    }

И я проверяю это с

class CdmFileSpec extends Specification {

    private CdmFile cdmFile
    private static final String filePath = 'src/test/resources/cdm/test/cdmFileTestFile.txt'

    void setup() {
        cdmFile = new CdmFile()
    }

    void 'test noFileExists'() {
        given:
        Path notRealPath = Paths.get('src/test/resources/cdm//test/notreal.txt')

        when:
        String fileContents = cdmFile.readFileContents(notRealPath)

        then:
        thrown NoSuchFileException
    }

    void 'test readFileContents() reads file contents'() {
        given:
        Path testFilePath = Paths.get(filePath)

        when:
        String fileContents = cdmFile.readFileContents(testFilePath)

        then:
        fileContents.contains('hip hop horrayy\n\nhoooo\n\nheyyy\n\nhoooo')
    }
}

Это работает, поскольку я поместил настоящий файл в filePath.

Мне интересно ... как я могу проверить следующий метод с помощью Mock?

void eachLineInFileAsString(Path filePath,
                                @ClosureParams(value = SimpleType, options = ['java.lang.String'] )Closure applyLine) {
        BufferedReader br = Files.newBufferedReader(filePath)
        String line
        while ((line = br.readLine()) != null) {
            applyLine.call(line)
        }
    }

Ответы [ 2 ]

1 голос
/ 27 июня 2019

Проблема с имитацией во многих случаях заключается в том, что методы создают свои собственные зависимости, а не вводят их или вызывают вызывающий метод службы, создающий их.Я предлагаю вам немного реорганизовать свой код, извлекая BufferedReader создание в метод сервиса:

package de.scrum_master.stackoverflow.q56772468

import groovy.transform.stc.ClosureParams
import groovy.transform.stc.SimpleType

import java.nio.charset.StandardCharsets
import java.nio.file.Files
import java.nio.file.Path

class CdmFile {
  String readFileContents(Path filePath) {
    StringBuilder fileContents = new StringBuilder()
    BufferedReader br = createBufferedReader(filePath)
    String line
    while ((line = br.readLine()) != null) {
      fileContents.append(line).append('\n')
    }
    fileContents
  }

  void eachLineInFileAsString(
    Path filePath,
    @ClosureParams(value = SimpleType, options = ['java.lang.String']) Closure applyLine
  ) {
    BufferedReader br = createBufferedReader(filePath)
    String line
    while ((line = br.readLine()) != null) {
      applyLine.call(line)
    }
  }

  protected BufferedReader createBufferedReader(Path filePath) {
    Files.newBufferedReader(filePath, StandardCharsets.UTF_8)
  }
}

Теперь макетирование довольно просто, и вам больше не нужен файл тестового ресурса (только еслиВы хотите выполнить интеграционный тест без макетов):

package de.scrum_master.stackoverflow.q56772468


import spock.lang.Specification

import java.nio.charset.StandardCharsets
import java.nio.file.NoSuchFileException
import java.nio.file.Path
import java.nio.file.Paths

class CmdFileTest extends Specification {
  private static final String filePath = 'mock/cdmTestFile.txt'
  private static final String fileContent = """
    I heard, that you're settled down
    That you found a girl and you're, married now
    I heard, that your dreams came true
    I guess she gave you things
    I didn't give to you
  """.stripIndent()

  private CdmFile cdmFile

  void setup() {
    cdmFile = Spy() {
      createBufferedReader(Paths.get(filePath)) >> {
        new BufferedReader(
          new InputStreamReader(
            new ByteArrayInputStream(
              fileContent.getBytes(StandardCharsets.UTF_8)
            )
          )
        )
      }
    }
  }

  def "non-existent file leads to exception"() {
    given:
    Path notRealPath = Paths.get('notreal.txt')

    when:
    cdmFile.readFileContents(notRealPath)

    then:
    thrown NoSuchFileException
  }

  def "read file contents into a string"() {
    given:
    Path testFilePath = Paths.get(filePath)

    when:
    String fileContents = cdmFile.readFileContents(testFilePath)

    then:
    fileContents.contains("your dreams came true\nI guess")
  }

  def "handle file content line by line"() {
    given:
    def result = []
    def closure = { line -> result << line }
    Path testFilePath = Paths.get(filePath)

    when:
    cdmFile.eachLineInFileAsString(testFilePath, closure)

    then:
    result == fileContent.split("\n")
  }
}

Обратите внимание, что я использую здесь Spy(), то есть оставляю исходный объект CdmFile нетронутым и просто указываю на метод обслуживания createBufferedReader(..)при вызове с точно параметром Paths.get(filePath).Для других путей вызывается оригинальный метод, который важен для несуществующего теста файлов или если вы хотите добавить тесты, связанные с загрузкой файлов реальных ресурсов, как в вашем собственном примере.

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

1 голос
/ 26 июня 2019

Нет необходимости в макете, так как вы можете просто использовать локально определенное замыкание:

def "test the method"() {
    given:
    def result = []
    def closure = { line -> result << line }
    Path testFilePath = Paths.get(filePath)

    when:
    eachLineInFileAsString(testFilePath, closure)

    then: // I'm guessing here
    result == [
        'line 1',
        'line 2',
        'line 3',
        'line 4'
    ]
}
...