如何使存根返回任何负数?

时间:2018-01-21 09:46:02

标签: javascript node.js mocha sinon chai

如果此客户至少有一个样品可用且订单金额确实符合配置的限制(缺失金额为负数),则只需显示“编辑”按钮。逻辑很简单,如何对任何负数进行测试,而不仅仅是-1?

// function to be tested
showEditButton: function () {
    return !this.getSamples().isEmpty() && this.getMissingAmount().getValue() <= 0;
}

// my lame test here
describe('showEditButton()', function () {
    it('should be true if the missing amount is negative and at least one available sample', function () {
        var samples = new Samples({}, {}, {});

        sinon.stub(samples, 'getMissingAmount').returns({
            getValue: sinon.stub().returns(-1) // I need any negative number here :(
        });

        sinon.stub(samples, 'getSamples').returns({
            isEmpty: sinon.stub().returns(false)
        });

        expect(samples.showEditButton()).to.be.true;
    });
});

2 个答案:

答案 0 :(得分:0)

  

如果此客户至少有一个样品可用,并且订单金额确实符合配置的限制(缺失金额为负数),则只显示“编辑”按钮。

我认为对任何负数进行测试并不重要,至少不是showEditButton,所以你可以尝试让getMissingAmount返回差异或者返回0

您唯一需要测试的是案例只有两个value <= 0>=1

describe('showEditButton()', function () {
    it('if the missing amount is negative and at least one available sample, showEditButton should be true', function () {
        var samples = new Samples({}, {}, {});

        sinon.stub(samples, 'getMissingAmount').returns({
            getValue: sinon.stub().returns(-1);
        });

        sinon.stub(samples, 'getSamples').returns({
            isEmpty: sinon.stub().returns(false);
        });

        expect(samples.showEditButton()).to.be.true;
    });

    it('if the missing amount is NOT negative and at least one available sample, showEditButton should be false', function () {
        var samples = new Samples({}, {}, {});

        sinon.stub(samples, 'getMissingAmount').returns({
            getValue: sinon.stub().returns(1);
        });

        sinon.stub(samples, 'getSamples').returns({
            isEmpty: sinon.stub().returns(false);
        });

        expect(samples.showEditButton()).to.be.false;
    });
});

您可以对getMissingAmount().getValue()函数进行测试,以便在每次调用时返回不同的结果。

// stub get getValue()
fn.onCall(0).returns(-100);
fn.onCall(1).returns(-50);
fn.onCall(2).returns(-25);
fn.returns(3);

fn(); // -100
fn(); // -50
fn(); // -25
fn(); // 3
fn(); // 3

答案 1 :(得分:0)

正如其他人所说的那样,你无法用'任何负数'来测试。对于这样的情况,您通常希望测试边界周围的值并假设其余部分可以正常工作。在这种情况下,这些值将为-1,0和1。

至于在摩卡中完成此操作,您有几种方法。您可以将所有这些案例分组到一个测试中,如下所示:

describe('showEditButton()', function () {
    it('should be true if missing amount is negative and at least one available sample', function() {
        var samples = new Samples({}, {}, {});
        sinon.stub(samples, 'getSamples').returns({
            isEmpty: sinon.stub().returns(false)
        });
        sinon.stub(samples, 'getMissingAmount').returns({
            getValue: sinon.stub()
                .onFirstCall().returns(-1)
                .onSecondCall().returns(0)
                .onThirdCall().returns(1)
        });

        expect(samples.showEditButton()).to.be.true;
        expect(samples.showEditButton()).to.be.false;
        expect(samples.showEditButton()).to.be.false;
    });
});

或者 - 更准确地说,如果您正在尝试遵循单元测试的最佳实践 - 您可以明确地为每个案例提供自己的测试,如下所示:

describe('showEditButton()', function () {
    var samples, missingAmount;

    beforeEach(function() {
        samples = new Samples({}, {}, {});
        missingAmount = { getValue: sinon.stub() };

        sinon.stub(samples, 'getSamples').returns({
            isEmpty: sinon.stub().returns(false)
        });
        sinon.stub(samples, 'getMissingAmount').returns(missingAmount);
    });

    it('should be true if missing amount is negative and at least one available sample', function() {
        missingAmount.getValue.returns(-1);

        expect(samples.showEditButton()).to.be.true;
    });

    it('should be false if missing amount is zero and at least one available sample', function() {
        missingAmount.getValue.returns(0);

        expect(samples.showEditButton()).to.be.false;
    });

    it('should be false if missing amount is positive and at least one available sample', function() {
        missingAmount.getValue.returns(1);

        expect(samples.showEditButton()).to.be.false;
    });
});

但是,在任何情况下,您都没有测试isEmpty的支票。为此,你可以这样做:

describe('showEditButton()', function () {
    var samples, getSamplesResult, missingAmount;

    beforeEach(function() {
        samples = new Samples({}, {}, {});
        missingAmount = { getValue: sinon.stub() };
        getSamplesResult = { isEmpty: sinon.stub() };

        sinon.stub(samples, 'getSamples').returns(getSamplesResult);
        sinon.stub(samples, 'getMissingAmount').returns(missingAmount);
    });

    context('no available samples', function() {
        it('should be false without getting missing amount', function() {
            getSamplesResult.isEmpty.returns(true);

            expect(samples.getSamples()).to.be.false;
            expect(samples.getMissingAmount.callCount).to.equal(0);
        });
    });

    context('at least one available sample', function() {
        beforeEach(function() {
            getSamplesResult.isEmpty.returns(false);
        });

        it('should be true if missing amount is negative', function() {
            missingAmount.getValue.returns(-1);

            expect(samples.showEditButton()).to.be.true;
        });

        it('should be false if missing amount is zero', function() {
            missingAmount.getValue.returns(0);

            expect(samples.showEditButton()).to.be.false;
        });

        it('should be false if missing amount is positive', function() {
            missingAmount.getValue.returns(1);

            expect(samples.showEditButton()).to.be.false;
        });
    });
});

请注意,context只是describe的别名,您可以在这种情况下使用它来使读者的目标更加清晰。

最后,如果你想变得非常花哨,你可以使用普通的JS函数来“参数化”你的测试用例。我通常不会走这么远,但如果你想要的话,这是可能的:

describe('showEditButton()', function () {
    var samples, getSamplesResult, missingAmount;

    beforeEach(function() {
        samples = new Samples({}, {}, {});
        missingAmount = { getValue: sinon.stub() };
        getSamplesResult = { isEmpty: sinon.stub() };

        sinon.stub(samples, 'getSamples').returns(getSamplesResult);
        sinon.stub(samples, 'getMissingAmount').returns(missingAmount);
    });

    context('no available samples', function() {
        it('should be false without getting missing amount', function() {
            getSamplesResult.isEmpty.returns(true);

            expect(samples.getSamples()).to.be.false;
            expect(samples.getMissingAmount.callCount).to.equal(0);
        });
    });

    context('at least one available sample', function() {
        beforeEach(function() {
            getSamplesResult.isEmpty.returns(false);
        });

        testCase(-1, true, 'negative');
        testCase(0, false, 'zero');
        testCase(1, false, 'positive');

        function testCase(value, expected, valueType) {
            it(`should be ${expected} if missing amount is ${valueType}`, function() {
                missingAmount.getValue.returns(value);

                expect(samples.showEditButton()).to.equal(expected);
            })
        }
    });
});