Как использовать заглушку с Cypress

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

Он имеет широкий спектр плагинов, которые могут быть использованы для расширения его функциональности. Кроме того, у него есть отличное сообщество, которое поможет вам начать работу с Cypress.

Что такое заглушка при тестировании приложений?

Заглушка — это фрагмент кода, который используется для замены другого фрагмента кода, который еще не доступен или не может дать желаемый результат.

Например, если тестируемому пакету необходимо выполнить вызов внешнего API, но API еще не создан, команда тестирования может использовать заглушку для имитации функциональности API.

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

Это позволяет продолжить тестирование без ошибок, а также дает возможность оценить, как поведет себя система, когда в нее будет интегрирован настоящий API.

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

Зачем использовать заглушки в своих приложениях?

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

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

Они могут быть доступны на вашей стороне, но могут быть недоступны, когда вы запускаете свои тесты в облаке или передаете их партнеру. С заглушками вы всегда будете уверены, что ваши тесты работают везде, не завися в значительной степени от API.

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

Другой случай использования заглушек в Cypress — иногда ваши тесты зависят от даты и времени вашего приложения, что создает неудобства для ваших тестов, поскольку делает ваше приложение зависимым от времени.

Вместо этого вы можете использовать функцию cy.clock(), которая поможет вам контролировать время вашего браузера и пропускать время.

Способы выполнения заглушек в Cypress

Cypress предоставляет множество функций для создания заглушек других функций, наиболее важными из них являются следующие:

cy.stub() полезна для заглушки любой функции или метода внутри вашего приложения, например: отключение функции prompt на объекте окна.

cy.intercept используется, когда вы хотите изменить данные запросов и ответов в сетях между вашим браузером и вашими API напрямую.

cy.spy() позволяет обернуть функцию и записать вызовы этой функции без фактической замены исходной функции.

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

Основное различие между cy.spy() и cy.stub() заключается в том, что cy.spy() не заменяет метод, а только оборачивает его. Таким образом, хотя вызовы записываются, исходная функция по-прежнему вызывается без изменений.

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

Примеры использования заглушек шпионов и часов

В этой статье я приведу несколько примеров использования заглушек, шпионов и часов в Cypress.

Заглушка вызовов API в Cypress с помощью cy.intercept()

Если вы используете современный front-end фреймворк для своих приложений, то, скорее всего, вы используете рендеринг на стороне клиента.

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

Для этого мы будем использовать команду cy.intercept() из Cypress.

Для этого примера я создал небольшое приложение, которое получает данные из JSON placeholder API.

Вот как это выглядит.

Все данные о делах поступают из JSON placeholder API.

Допустим, мы хотим заглушить ответ, который мы получаем от API, и получить в теле ответа пользовательский ответ.

Допустим, вы хотите получить только две записи из API напрямую.

Для этого я создам JSON-файл в папке fixtures, которую предоставляет cypress, и вставлю туда данные.

Fixtures — это статические наборы данных в расположенном файле, которые вы можете использовать в своих тестах.

Фикстура cypress/fixtures/todos.json.

[
    {
        "userId": 1,
        "id": 1,
        "title": "First todo",
        "completed": false
    },
    {
        "userId": 1,
        "id": 2,
        "title": "Second todo",
        "completed": false
    }
]
Вход в полноэкранный режим Выход из полноэкранного режима

Файл спецификации

describe("My todo app", () => {
  it("Gets back only two entries", () => {
    cy.intercept("https://jsonplaceholder.typicode.com/todos*", {
      fixture: "todos.json",
    })
    cy.visit("/")

    cy.get("[data-cy=todo-item]").should("have.length", 2)
  })
})
Вход в полноэкранный режим Выход из полноэкранного режима

Обратите внимание, что мы поставили * после полного URL, это означает, что для всех различных параметров запроса осуществляется перехват.

Также убедитесь, что вы поставили cy.intercept() перед cy.visit(), потому что иногда запрос отправляется без полного завершения функции перехвата, что приводит к неудаче вашего теста.

Вы также можете изменить метод запроса, указав метод запроса в первом параметре, например:

cy.intercept("GET", "https://jsonplaceholder.typicode.com/todos*", {
  fixture: "todos.json",
})
Войти в полноэкранный режим Выйти из полноэкранного режима

Если вы не хотите использовать приспособление, вы можете изменить перехват, указав в теле значение.

cy.intercept("GET", "https://jsonplaceholder.typicode.com/todos*", {
  body: [{ title: "First" }, { title: "Second" }],
})
Ввести полноэкранный режим Выйти из полноэкранного режима

Вы также можете изменить другие свойства запроса, например, заголовки

cy.intercept("https://jsonplaceholder.typicode.com/todos*", {
  body: [{ title: "First" }, { title: "Second" }],
  headers: {
    Authorization: "Bearer <token>",
  },
})
Войти в полноэкранный режим Выйти из полноэкранного режима

Заглушка функций и свойств с помощью команды cy.stub()

Cypress позволяет создавать заглушки функций и свойств с помощью команды cy.stub().

Функция принимает два аргумента, один из которых — объект, а второй — метод, который вы хотите заглушить.

Как использовать stub в cypress

Пример использования cy.stub() в Cypress

describe("Stubbing", () => {
  const obj = {
    sum: (a: number, b: number) => a + b,
  }

  it("should stub the function", () => {
    cy.stub(obj, "sum").returns(3) // returns 3 instead of a + b

    expect(obj.sum(10, 20)).to.equal(3)
  })
})
Вход в полноэкранный режим Выйти из полноэкранного режима

Как вы видите, функция всегда будет возвращать 3, независимо от того, какие входные данные используются.

Заглушение функции на основе количества вызовов

Иногда мы хотим изменить возвращаемые значения функции в зависимости от количества вызовов этой функции.

Если вы хотите получить некоторое значение при первом вызове функции и другое значение при втором и третьем вызове, вы можете добиться этого, используя методы onFirstCall(), onSecondCall() и onThirdCall().

it("should stub the function for the first 3 calls", () => {
    cy.stub(obj, "sum")
        .onFirstCall()
        .returns(3)
        .onSecondCall()
        .returns(10)
        .onThirdCall()
        .returns(20)

    expect(obj.sum(10, 20)).to.equal(3)
    expect(obj.sum(10, 20)).to.equal(10)
    expect(obj.sum(10, 20)).to.equal(20)
})
Вход в полноэкранный режим Выход из полноэкранного режима

Метод onFirstCall() позволяет изменить функцию только для первого вызова, методы onSecondCall() и onThirdCall() делают то же самое для второго и третьего вызова функции.

Восстановление заглушенного метода

Иногда вы хотите заглушить метод только один раз и восстановить его до исходного метода, запущенного определенное количество раз.

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

it("should stub and restore the function", () => {
    const stub = cy
        .stub(obj, "sum")
        .onFirstCall()
        .returns(3)
        .onSecondCall()
        .returns(10)
        .onThirdCall()
        .returns(20)

    expect(obj.sum(10, 20)).to.equal(3)
    expect(obj.sum(10, 20)).to.equal(10)
    expect(obj.sum(10, 20)).to.equal(20)

    stub.restore()

    expect(obj.sum(10, 20)).to.equal(30)
})
Вход в полноэкранный режим Выход из полноэкранного режима

Заглушка свойства

Заглушки используются не только для методов, вы можете создавать заглушки свойств объектов и изменять их значения с помощью метода value().

describe("Stub a property", () => {
  const car = {
    color: "red",
    getColor() {
      return this.color
    },
  }

  it("should stub a property", () => {
    expect(car.getColor()).to.equal("red")

    cy.stub(car, "color").value("blue")

    expect(car.getColor()).to.equal("blue")
  })
})
Вход в полноэкранный режим Выход из полноэкранного режима

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

describe("Stub a property", () => {
  const car = {
    color: "red",
    getColor() {
      return this.color
    },
  }

  it("should stub a property", () => {
    expect(car.getColor()).to.equal("red")

    cy.stub(car, "color").value({ message: "blue" })

    expect(car.getColor()).to.deep.equal({ message: "blue" })
  })
})
Войти в полноэкранный режим Выход из полноэкранного режима

Действия и заглушки приложений Cypress

С помощью Cypress мы можем легко создавать заглушки методов и функций непосредственно внутри нашего приложения.

Как работают действия приложений Cypress?

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

Например, вы можете написать в своем приложении JavaScript следующего содержания

  if (window.Cypress) {
    window.actions.myMethod = myMethod
  }
Войти в полноэкранный режим Выйти из полноэкранного режима

Таким образом, вы можете использовать это внутри ваших тестов Cypress

cy.window().its("actions").invoke("myMethod")
Войти в полноэкранный режим Выйти из полноэкранного режима

Поскольку действия приложения можно легко использовать внутри тестов Cypress, мы можем легко заглушить их и изменить возвращаемое значение.

it("should stub a method with app actions", () => {
  cy.visit("/")
  cy.window()
    .its("actions")
    .then((actions) => {
      cy.stub(actions, "myMethod").returns(20)
    })

  cy.window().its("actions").invoke("myMethod").should("eq", 20)
})

Вход в полноэкранный режим Выйти из полноэкранного режима

Узнать о действиях приложений можно здесь.

Написать собственную логику в заглушенном методе

Иногда вы хотите не просто изменить возвращаемое значение функции или метода, а изменить логику работы функции.

Вы можете сделать это, вызвав метод callsFake().

it("should stub a method with app actions", () => {
  cy.visit("/")
  cy.window()
    .its("actions")
    .then((actions) => {
      cy.stub(actions, "myMethod").callsFake(() => {
        // some logic
        return "Output with logic"
      })
    })

  cy.window()
    .its("actions")
    .invoke("myMethod")
    .should("eq", "Output with logic")
})
Вход в полноэкранный режим Выход из полноэкранного режима

Использование функции Spy в Cypress

Функция шпионажа полезна тем, что позволяет узнать, что функция была вызвана с правильными аргументами или счетчик вызовов функции, или определить возвращаемое значение функции-шпиона.

Шпион не изменяет поведение функции — она остается совершенно нетронутой. Шпион наиболее полезен, когда вы тестируете контракт между несколькими функциями и вас не волнуют побочные эффекты, которые может создать настоящая функция (если таковые имеются).

Разница между шпионами и заглушками

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

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

Пример использования шпиона с Cypress

describe("Using Spy", () => {
  const obj = {
    color: "red",
    getColor() {
      return this.color
    },
    setColor(color: string) {
      this.color = color
    },
  }

  it("should spy the function", () => {
    cy.spy(obj, "getColor")

    obj.getColor()

    expect(obj.getColor).to.have.been.called

    cy.spy(obj, "setColor")

    obj.setColor("blue")

    expect(obj.setColor).to.have.been.calledWith("blue")

    obj.getColor()

    expect(obj.getColor).to.have.returned("red")
  })
})
Вход в полноэкранный режим Выход из полноэкранного режима

В этом примере мы убеждаемся, что функция getColor() была вызвана хотя бы один раз.

Также мы убеждаемся, что функция setColor() была использована с правильными аргументами.

Также мы убеждаемся, что функция getColor() возвращает правильные значения.

Если вы не запустите эту функцию, ваше утверждение будет неудачным.

it("should spy the function", () => {
    cy.spy(obj, "getColor")

    // failing test on purpose
    expect(obj.getColor).to.been.called
})
Вход в полноэкранный режим Выход из полноэкранного режима

Манипулирование временем с помощью функций clock() и tick() в Cypress

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

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

Чтобы управлять временем браузера, используйте команду cy.clock() для инициализации и используйте команду cy.tick() для перехода через время.

Команда cy.tick() принимает аргумент — количество времени, которое должно пройти в миллисекундах.

describe("My todo app", () => {
  it("Should skip through time", () => {
    cy.clock(new Date())
    cy.visit("/")
    cy.tick(10000) // ten seconds
  })
})
Вход в полноэкранный режим Выйти из полноэкранного режима

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

Часы браузера отличаются от часов спецификации

Обратите внимание, что использование команды cy.clock() изменит только часы приложения, а не часы спецификации, которые находятся вне приложения.

it("should not have the same time as the spec's time", () => {
  cy.clock(new Date(Date.UTC(2022, 8, 20)), ["Date"])
  cy.visit("/")
  cy.window().its("Date").invoke("now").should("not.equal", Date.now())
})
Вход в полноэкранный режим Выход из полноэкранного режима

Как вы можете видеть, дата приложения полностью отличается от даты и времени в спецификации.

Заключение

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

Если у вас есть какие-то замечания, сообщите нам об этом ниже 👇

Оцените статью
devanswers.ru
Добавить комментарий