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 -
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.