【问题标题】:Should I mock every single dependencies in unit testing?我应该在单元测试中模拟每个依赖项吗?
【发布时间】:2020-05-14 08:49:14
【问题描述】:

经过大量阅读,我发现人们建议在单元测试的方法中模拟每个依赖项。

Should I mock all the dependencies when unit testing?

When should I mock?

但是,我有一个创建对象列表(依赖项)并使用这些对象的方法来更改列表的方法。在实际场景中,该方法是将客户端发送的数据负载转换为这些对象。 下面是 Typescript 中的代码实现,但它只是给你一个想法。

import {expect} from 'chai';

import 'mocha';

class Bar {
    private val: number;

    constructor(val: number) {
        this.val = val;
    }

    isValid(): boolean {
        return this.val !== 2;
    }

    canMergeWith(bar: Bar): boolean {
        return this.val === bar.val;
    }
}

class BarBuilder {
    constructor() {
    }

    createBars(payload: number[]): Bar[] {
        const bars: Bar[] = [];
        payload.forEach(p => {
            bars.push(new Bar(p));
        });

        const filtered = this.filterBars(bars);
        const merged = this.mergeBars(filtered);
        return merged;
    }

    private filterBars(bars: Bar[]): Bar[] {
        return bars.filter(b => b.isValid());
    }

    private mergeBars(bars: Bar[]): Bar[] {
        const merged: Bar[] = [];
        bars.forEach((bar, i) => {
            if (i > 0) {
                const before = bars[i - 1];
                if (!bar.canMergeWith(before)) {
                    merged.push(bar);
                }
            } else {
                merged.push(bar);
            }
        });
        return merged;
    }
}

describe('BarBuilder', () => {
    it('Should convert payload into valid bars', () => {
        const payload = [1, 2, 3, 4, 4, 5, 5];
        const barBuilder = new BarBuilder();
        const bars = barBuilder.createBars(payload);
        expect(bars).to.deep.equal([{val: 1}, {val: 3}, {val: 4}, {val: 5}]);
    });
});

目前,测试正在通过。但这违反了我应该模拟类中的每个依赖项的规则。

我应该做以下哪一项:

  1. 我真的应该模拟 Bar 类以遵守该规则吗?

如果是这样,我发现这样做还有另一个困难。如果我模拟 Bar 类,如何使模拟方法 canMergeWithisValid 根据输入返回 true 或 false?不等于重写类本身吗?

  1. 我应该重构我的代码吗?

我也在想问题可能在于我的代码不可测试。之前,方法canMergeWithisValid 属于BarBuilder。为了便于阅读,我将它们移到了 Bar 中。但是现在,BarBuilder 的单元测试已经不再繁琐了。

  1. 尽管测试违反了单元测试规则,但仍保持原样。

【问题讨论】:

    标签: unit-testing oop language-agnostic


    【解决方案1】:

    我发现人们建议在单元测试下模拟方法中的每个依赖项。

    有些人建议这样做,是的。在链接的线程中,更多的人不同意。单元测试实际上是一个分裂的话题。

    当我第一次得知没有被整个行业广泛接受的单元测试定义时,我感到很惊讶。人们经常谈论单元测试,好像只有一个定义,尤其是“模拟一切”的定义;但如果您通读链接的线程,您会发现这种方法存在许多缺陷,尤其是这些测试的脆弱性。

    我认为“模拟一切”的定义仍然如此普遍,因为它是多么微不足道。没有任何想法,只是嘲笑一切。另一种方法是考虑何时模拟,何时不模拟。那更难。你必须证明嘲笑是正当的。将单元测试定义为“模拟一切”更容易,因为这样您就不会考虑模拟的目的。这只是定义的一部分。

    Ian Cooper 发表了关于单元测试的演讲,正如 Kent Beck 在 TDD 的上下文中定义的那样。我发现他的观点比“模拟一切”的方法更现代。

    Kent 以一种非常具体的方式使用单元测试。当他使用这个短语时,他的意思是您应该能够将所有测试作为一个套件一起运行,而运行的一个测试不会影响其他测试。 隔离单元是测试。 因为人们认为隔离单元是被测试的类,所以犯了很多错误。不是。

    我的建议:当他们帮助你时创建模拟。不要创建模拟来满足规则。没有规则背后的共识。

    【讨论】:

      猜你喜欢
      • 2014-07-01
      • 1970-01-01
      • 2023-03-13
      • 1970-01-01
      • 1970-01-01
      • 2013-07-07
      • 1970-01-01
      • 2016-02-19
      • 2012-07-11
      相关资源
      最近更新 更多