Giter Club home page Giter Club logo

feather's Introduction

Platforms Platforms Actions Status

logo

Feather is a simple lightweight solution to enable mocking in UI tests for Swift projects.

Mocking is an important part of testing. However, unlike unit tests, mocking is harder to achieve in UI tests as we do not import the main app into the UITest target. This means we do not have access to the underlying code, such as objects and functions, to use techniques like DI to inject mocks.

Feather enables mocking by spinning up a temporary local server on-device, giving you full control to map mock responses for API calls without having an intrusive footprint in your code.

Features

  • ๐Ÿ’‰ Simple API to inject mock API responses into UI Tests with minimum effort and footprint!

  • ๐Ÿ“ฑ Spins up a local server on-device/simulator and tears down once UITest Target has stopped running!

  • ๐Ÿš€ Dynamically update mock responses at run time!

  • ๐Ÿคธ Flexible API allowing various ways to provide mock responses!

  • ๐Ÿ‘จโ€๐Ÿ’ป Written in 100% Swift using Swift Vapor

Installation

Swift Package Manager

There are two steps needed for Feather to work in your UITest target.

1. Add Package to project

2. Add Feather to UITest Target

SPM does not automatically add Feather to your UITest target, so the below steps have to be done manually from Xcode:

  • Select your UITest target
  • Select the Build Phases tab
  • Add Feather in the "Link Binary With Libraries" section using the + button

logo

You should now be able to import Feather into your UITest target.

Usage

Mock Routes

Before understanding how Feather's mock server is configured, a key concept of Feather to understand is the MockRoute object. A mock route declares the following information:

  • The HTTP method the route will use
  • The endpoint to which the route will be mapped to
  • The status code to return for the response
  • A JSON string to be used as the mock response
    • As shown below, there are various ways of providing the JSON response

All API requests for a given UITest need to be mapped to a mock route. Feather achieves this mapping by injecting these routes from the UITest target into the mock server.

Declaring Mock Routes

You can declare routes in 3 ways as shown below, each with a different way of providing the mock response:

Using a JSON file

MockRoute(method: .get,
          endpoint: "user",
          code: 200,
          filename: "get_user_200")

Using an Encodable object

MockRoute(method: .get,
          endpoint: "user",
          code: 200,
          object: User.mock())

Using a JSON String

let jsonString = """
{
 "name": "John Doe",
 "username": "JohnD",
 "email": "[email protected]"
}
"""
   
MockRoute(method: .get,
          endpoint: "user",
          code: 200,
          json: jsonString)

Configuring the Mock Server

Starting the Server

The server can be created via the following initializer:

Feather(host: "localhost", port: 8080)

The above example will create the server at the address http://localhost:8080 when started.

Note that the host parameter is optional, by default the host will be set to "localhost".

Once configured, the server is started by calling the startServer(with:) function, passing in an array of MockRoute's

Stopping the Server

The server can be stopped by calling the pluck() function.

Setting the base URL

The final step to ensure your app correctly points to Feather's mock server is to update the base URL used to make API calls.

The simplest approach is to set the base URL inside the launchEnvironment dictionary on the XCUIApplication before you launch the UITest target as shown below:

app.launchEnvironment["baseUrl"] = feather.baseUrl

Your main app target will then receive the base URL as an environment argument. Depending on your app architecture you can then use this to prefix your API calls accordingly.

An example of this is shown below

 private var baseUrl: String {
  return ProcessInfo.processInfo.environment["baseUrl"] ?? "https://api.myCompany.com"
 }

Example

A typical setup for a UITest using Feather is shown below:

import XCTest
import Feather

final class ExampleUITests: XCTestCase {
   
  var app: XCUIApplication!
  var feather: Feather!
   
  override func setUp() {
    super.setUp()
    feather = Feather(port: 8080)
    app = XCUIApplication()
    app.launchEnvironment["baseUrl"] = feather.baseUrl
  }
   
  override func tearDown() {
    feather.pluck()
    feather = nil
    app = nil
    super.tearDown()
  }
   
  func test_example() {
    let routes: [MockRoute] = [.init(method: .get,
                                     endpoint: "user",
                                     code: 200,
                                     object: User.mock())]
     
    feather.startServer(with: routes)
    app.launch()
     
    // Test Assertions
    ...
    ...
  }
}

Dynamic Routes

Sometimes a response for a given endpoint may need to be changed at runtime.

For example, if you are testing adding items to a basket, your test may need to assert against a response that reflects an empty state, and then another response with items added.

To modify responses you can call one of the three updateRoute functions, passing in the updated JSON response, as well as the HTTP method and endpoint parameters which are used to identify the mock route to update.

feather.updateRoute(method: .get, endpoint: "user", object: User.mock(username: "Jane"))

Demo App

The repo contains a simple demo app that gives an example of how to use Feather in your UITest target, with various UI tests to demonstrate the different functions of Feather.

logo

Limitations

Feather was created as a bare-bones solution for a specific project, as a result, it is currently limited in scope. Below are some note worthy limitations that we aim to address in the future:

  • Our mock routes are very basic, we do not support query params, timeouts, or redirects
  • Unable to support test parralisation. This will be spported shortly by dynamically setting the server port to one that is available, meaning multiple servers can be spun up in parrallel.

For a more mature solution check our Shock by the team over at Just Eat Takeaway.

Contributions

If you feel you have a valuable feature to add or fix a bug, feel free to raise a PR.

License

Feather is available under Apache License 2.0. See the LICENSE file for more info.

feather's People

Contributors

ssh88 avatar

Stargazers

 avatar Jonas Simkus avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.