我有一个函数,它从要返回的数组中选择一个随机值:
export function selectMovieUnderDuration(options: IStreamRequest, movies: Movie[], prevMovies: Movie[], duration: number): Movie {
let filteredMovies: Movie[] = movies.filter(movie =>
movie.Tags.some(tag => options.Tags.includes(tag)) &&
movie.DurationLimit <= duration
);
let notRepeatMovies: Movie[] = filteredMovies.filter((item) => !prevMovies.some((obj) => obj.LoadTitle === item.LoadTitle));
let selectedMovie: Movie = notRepeatMovies.length > 0 ?
notRepeatMovies[Math.floor(Math.random() * notRepeatMovies.length)] :
filteredMovies[Math.floor(Math.random() * filteredMovies.length)];
return selectedMovie;
}
我知道经过多次现场测试后它可以正常工作,但我想在 mocha/chai 中为此编写一些自动化测试。
我已经进行了一些涵盖基本功能的测试:
describe('selectMovieUnderDuration', () => {
it('should return a movie that is under the duration limit that has the tags in the request object', () => {
let movies: Movie[] = [inception, matrix, interstellar, dune];
let prevMovies: Movie[] = [];
let args: ContStreamRequest = new ContStreamRequest('password', 'title', 'env', [], ['Sci-Fi']);
let result = proEng.selectMovieUnderDuration(args, movies, prevMovies, 9000);
expect(result).to.be.equal(inception);
});
it('should return a movie that is under the duration limit that has the tags in the request object and has not been selected before', () => {
let movies: Movie[] = [inception, matrix, interstellar, dune];
let prevMovies: Movie[] = [inception, matrix, dune];
let args: ContStreamRequest = new ContStreamRequest('password', 'title', 'env', [], ['Sci-Fi', 'Action']);
let result = proEng.selectMovieUnderDuration(args, movies, prevMovies, 10800);
expect(result).to.be.equal(interstellar);
});
});
但是,我现在想至少编写一个测试,其中“movies”数组中可用的所有项目也都在“prevMovies”数组中,因此它被迫选择以前受“prevMovies”限制的任何值“数组。
我知道我可以写这样的东西:
it('should return any movie that is under the duration limit that has the correct tags, when all movies with the criteria have been selected before', () => {
let movies: Movie[] = [inception, matrix, interstellar, dune];
let prevMovies: Movie[] = [inception, matrix, interstellar, dune];
let args: ContStreamRequest = new ContStreamRequest('password', 'title', 'env', [], ['Sci-Fi', 'Action']);
let result = proEng.selectMovieUnderDuration(args, movies, prevMovies, 9000);
expect(result).to.be.oneOf([inception, matrix]);
});
虽然这对于这种情况非常有用,因为我知道函数运行正常,但如果函数运行不正确并且我编写了这个测试,有时函数会返回沙丘或星际,但只是有时,测试有时只会失败。
有没有办法确保测试始终通过或始终失败?我正在考虑我可能需要重写该函数以分解某些部分并使它们可以单独测试,但这对于该函数已经非常简单来说似乎非常精细。
一般来说,您希望测试用例具有确定性,以便它们每次都以相同的方式运行,并且可以运行 100 次,并且每次都会发生相同的事情。
如果您需要随机测试某些内容,那么您需要详尽地断言所有可能的结果
举个例子,如果我有一个函数选择 1 到 10 之间的随机数,并且我想确保它有效:
export function getRandomNumber() {
return Math.floor( Math.random() * 10 )
}
这本质上是一个糟糕的测试:
let result = getRandomNumber();
expect(result).to.be.oneOf([1, 2]);
它有时会通过,有时会失败,因为断言对于所有可能的输出并不详尽。
你需要类似的东西:
let result = getRandomNumber();
expect(result).to.be.below(11);
expect(result).to.be.above(0);
因为这实际上涵盖了函数的所有可能输出。
因此,在您的示例中,您需要弄清楚该函数的所有可能输出是什么,并检查结果是否是其中任何一个,如果您在该检查中缺少可能的返回值,那么您最终会得到一个“随机”失败的片状测试。