10
单元测试应用程序逻辑和不信任的语言构造之间的界线在哪里?
考虑这样的函数: function savePeople(dataStore, people) { people.forEach(person => dataStore.savePerson(person)); } 可以这样使用: myDataStore = new Store('some connection string', 'password'); myPeople = ['Joe', 'Maggie', 'John']; savePeople(myDataStore, myPeople); 让我们假设它Store具有自己的单元测试,或由供应商提供。无论如何,我们都相信Store。让我们进一步假设错误处理(例如,数据库断开错误)不是的责任savePeople。确实,让我们假设商店本身是一个神奇的数据库,它不可能以任何方式出错。 鉴于这些假设,问题是: 应该savePeople()进行单元测试,还是将这些测试等同于测试内置forEach语言结构? 当然,我们可以传递一个模拟dataStore并断言dataStore.savePerson()每个人都会被调用一次。您当然可以说这样的测试可提供针对实现更改的安全性的论据:例如,如果我们决定forEach用传统的for循环或某种其他迭代方法代替。因此,测试并非完全无关紧要。但是它似乎非常接近... 这是另一个可能更富有成效的例子。考虑一个仅协调其他对象或功能的功能。例如: function bakeCookies(dough, pan, oven) { panWithRawCookies = pan.add(dough); oven.addPan(panWithRawCookies); oven.bakeCookies(); oven.removePan(); } 假设您认为这样的功能应该如何进行单元测试?这是我很难想象任何种类的单元测试的不只是嘲笑dough,pan和oven,然后断言方法被调用它们。但是这样的测试无非是复制了该函数的确切实现。 无法以有意义的黑盒方式测试功能是否表明功能本身存在设计缺陷?如果是这样,如何改进? 为了更清楚地说明激发bakeCookies示例的问题,我将添加一个更现实的场景,该场景是我尝试向其添加代码并重构遗留代码时遇到的一种情况。 当用户创建新帐户时,需要做很多事情:1)需要在数据库中创建新用户记录2)需要发送欢迎电子邮件3)需要记录用户的IP地址以防欺诈目的。 因此,我们想创建一个将所有“新用户”步骤联系在一起的方法: function createNewUser(validatedUserData, emailService, dataStore) …