我有以下测试案例:
it('is to show welcome message', () => {
spyOnProperty(authServiceSpy, 'token').and.returnValue(environment.testAuthenticationToken);
let teacher: Teacher = authServiceSpy.token.teacher;
let welcome: HTMLElement = ne.querySelector('#welcome-msg');
expect(welcome).toBeTruthy();
expect(welcome.innerHTML).toEqual(`Welcome ${teacher.firstName}`);
});
修改为environment.testAuthenticationToken
:
testAuthenticationToken: {
"type": "teacher",
"emailVerified": true,
"teacher": {
"_id": "0000000000000000000000000",
"title": "Teacher-X",
"firstName": "X",
"lastName": "X",
"locale": "en-US",
...
"emailVerified": true,
...
}
}
这是相应的模板html
<div id="welcome-msg">Welcome X</div>
如果我使用的是TDD,因此从测试开始,然后进行一个最小的实现,使测试通过,那么在这种情况下,我会在HTML X
中用硬编码老师的姓名< / em>。测试通过了,尽管在一般情况下实现被破坏了。如果我停止了这一天的工作,第二天又来运行测试,我可能会认为,由于测试通过,所以代码中可能没有问题。
这是预期结果,重构是下一步可能检测到的结果,还是使用随机预期来规避此结果?还是我走错路了?
谢谢。
答案 0 :(得分:1)
如果我在这一天停止工作,第二天又来运行测试,我可能会认为,由于测试通过,所以代码中可能没有问题。
对此特定问题的一个常见答案是更改您的工作例程,以便一天回家时总会出现测试失败的情况。第二天早上,失败的测试充当书签,使您回到工作的环境。
当然,您通常不会在这种状态下发布代码。
当肯特·贝克(Kent Beck)在他的书中描述TDD时,该过程包括他希望编写的测试清单。当他想到新的想法时,他可能会花一点时间写下来,然后继续进行当前的工作。他后来发现的有趣的测试将被剔除。
当列表中的所有项目都被划掉并且您想不出要添加的任何新项目时,操作就会完成。
如果您的测试目的是 也是文档,那么应该直接阅读已实现的测试列表以发现差距。凯夫琳·亨尼(Kevlin Henney)在MRU清单/ leap年计算/堆栈方面的演讲表明,当问题很小时,会是什么样子。
当然,您也可以通过... 测试代码来发现缺陷。或者,是X以外的其他人第一次使用该代码时就报告错误(假设故障导致了failure)
答案 1 :(得分:0)
这个问题与TDD方法有关,而不是它在有角前端中的应用
进行测试时,“随机”是禁止的词。除非您没有明确地故意制造混乱,否则所有内容都应该是可重现的:mutation testing的工作是这样,它有助于捕获一些无用的测试或某些情况,在这种情况下不会从测试中检测到错误的实现
但是,我坚持不懈地提出这个例子
describe("authServer.login()" , () => {
it("should return true if the user exists and password valid" , () => {
let result = uut.login("VALIDUSER" , "VALIDPASSWORD")
expect(result).to.be.true
})
})
我可以简单地通过
function login (username, password) {
return true
}
现在,如何迫使我更改该实现以使我的功能有价值?
1)不要从幸福的道路开始
通常,当我们编写新代码时,我们从快乐的路径开始,然后添加所有需要的异常(不打算作为软件异常:-D)处理。这根本没有错,实际上是一种非常敏捷的方法,因为它使您可以编写一些工作代码,而不必费神思索所有事情。但是,如果我们有能力并且很幸运,有时将我们的代码拆分为许多小组件并预先设计其行为并不难。在登录情况下,很容易从
开始describe("authServer.login()" , () => {
it("should return false if the user doesnt exists" , () => {
let result = uut.login("NOTFOUNDUSER" , "VALIDPASSWORD")
expect(result).to.be.false
})
})
function login (username, password) {
return false
}
但是,由于您对自己的前进道路不满意,因此必须进行更改
2)从代码中“期望更多”
这是一个令人争论的论点,鲍勃叔叔在其“清洁代码”中写道:在测试中包含多个断言是一种好习惯吗?我没有比参加这场辩论的人更好,但是我可以通知,定义了功能的每组数据都可以划分为“等价类”,因为开发人员编写的功能不是内射的,因此添加了两个断言来自同一个等价类的问题就像拥有一个等价类,但有更多的约束条件
describe("sum()" , () => {
it("should sum correctly two addends , () => {
expect(sum(3,7)).to.eq(10)
expect(sum(1,2)).to.eq(3)
})
})
现在您不能再对数字进行硬核了。如果确实困扰您,那么您就可以摆脱两者之一了
3)重构不仅仅是编写更好的代码
但也可以使其在不改变黑匣子行为的情况下正常工作。当您的婴儿步骤通过测试后,您必须返回代码进行审查,这是tdd周期!在这种情况下,您会注意到生产代码是一个骗局,您将对其进行处理。如果您没有时间,因为您的队友在逼您去吃午饭,在推动之前故意弄乱了测试
describe("authServer.login()" , () => {
it("should return true if the user exists and password valid" , () => {
let result = uut.login("VALIDUSER" , "VALIDPASSWORD")
expect(result).to.be.true
expect(true).to.be.false //<----- Have a Nice meal
})
})
除此之外,请记住,在TDD中测试是活的东西,它们随着代码的变化而变化,您可以利用它