简体   繁体   中英

How to implement Jest Mocks?

I am using the Jest framework and am trying to implement a mock of a function. I have a small airport app that allows a user to takeoff and land planes but it must be restricted due to random weather.

The weather is in another class and is randomised, for my tests I need to mock the weather function to always return true on one test and false on others.

The difficulty I have is how exactly to implement the mock function? The docs talk of using jest.fn and setting it to a constant variable but this confuses me as I do not understand how jest.fn can equate to a function when it's not fed the function name. The further jest mock docs, while comprehensive, are a bit inaccessible to someone learning and most other resources I have are resulting in the same confusion. In essence I am hoping for a layman's terms guide to implementing this? Such as -

  • how to correctly declare a function as mocked?
  • how to explicitly declare the return value of that function?
  • how to call that mock function within my test suite?

TESTS:

const Airport = require('./airport')
const Plane = require('./plane')
const Weather = require('./weather')

airport = new Airport('Bristol')
plane = new Plane('Boeing 747')


test('the airport lands a plane', () => {
  expect(airport.land(plane)).toBe(1);
});

test('the airport allows a plane to take off', () =>{
  expect(airport.takeOff()).toBe(0);
});

test('the airport has a default capacity of 1 when constructed', () => {
  bath = new Airport('Bath')
  expect(bath.capacity).toBe(1)
})

test('The airports default capacity can be defined at construction', () => {
  bristol = new Airport('Bristol', 5)
  expect(bristol.capacity).toBe(5)
});

test("The airport doesn't let you land when the hangar is full", () => {
  wells = new Airport('Wells', 1)
  plane2 = new Plane('Spitfire')
  wells.land(plane)
  expect(wells.land(plane2)).toBe('HANGAR FULL LANDING DENIED')
});

test("The airport doesn't let you land when weather is stormy", () =>{
  york = new Airport('york', 1)
//  york.weather = true
  plane = new Plane('plane')
  expect(york.land(plane)).toEqual('LANDING DENIED POOR WEATHER')
});

Airport file being tested:

const Weather = require('./weather')

class Airport {
  constructor(name, capacity = 1, weather = new Weather) {
    this.name = name;
    this.hangar = [];
    this.capacity = capacity;
    this.weather = weather.getWeather();
  }

   land (plane) {
     if (this.weather === true) {
       return 'LANDING DENIED POOR WEATHER'
     } else if (this._isFull() === false) {
       this.hangar.push(plane)
     return this.hangar.length
   } else {
     return 'HANGAR FULL LANDING DENIED'
   }
   };


  takeOff () {
   this.hangar.pop()
   return this.hangar.length;
 };

  _isFull () {
   if (this.hangar.length < this.capacity) {
     return false
   } else {
     return true
   }
  };

};

module.exports = Airport;

Weather class with random weather function:

class Weather {

  getWeather() {
    var chance = Math.floor(Math.random() * 10)
    if (chance <= 3) { return true } else { return false }
  }
}

module.exports = Weather;

You can see in the file that I have found a bad way of overriding the weather, by manually setting the property in airport to true, I have been informed this is a code smell though and wish to refactor to a proper mock function/module/class.

Your Airport class is set up to get the weather using dependency injection .

It will call getWeather on the third parameter passed to the constructor (or a new instance of Weather if none is provided) to set the weather for the Airport .

You can use this dependency injection to provide a mock implementation of the Weather dependency to set the desired weather for the test:

test("The airport doesn't let you land when weather is stormy", () =>{
  const york = new Airport('york', 1, { getWeather: () => true })  // always bad weather
  const plane = new Plane('plane')
  expect(york.land(plane)).toEqual('LANDING DENIED POOR WEATHER')  // SUCCESS
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM