Angular 如何避免考试同时通过

Angular 如何避免考试同时通过,angular,jasmine,tdd,bdd,Angular,Jasmine,Tdd,Bdd,我有以下测试用例: it('is to show welcome message', () => { spyOnProperty(authServiceSpy, 'token').and.returnValue(environment.testAuthenticationToken); let teacher: Teacher = authServiceSpy.token.teacher; let welcome: HTMLElement = ne.querySe

我有以下测试用例:

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}`);
});
moded
环境。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>
Welcome X
如果我使用TDD,因此从测试开始,然后使用一个使测试通过的最小实现,那么在这种情况下,我会在HTML
X
中硬编码教师的姓名。尽管在一般情况下实现被破坏,但测试还是通过了。如果我在这一天停止工作,第二天来运行测试,我可能会认为既然测试通过了,代码中可能就没有问题了

这是一个预期的结果,重构是下一步可能检测到的结果,还是使用随机期望来规避这个结果?还是我走错了方向

谢谢

如果我在这一天停止工作,第二天来运行测试,我可能会认为既然测试通过了,代码中可能就没有问题了

对于这一问题,一个常见的答案是改变你的工作程序,这样当你回家一天时,总有一次考试不及格。第二天早上,失败的测试就像一个书签,把你带回你工作的环境

当然,您通常不会在这种状态下发布代码

当Kent Beck在他的书中描述TDD时,这个过程包括了他希望编写的测试的检查表。当他想到新的想法时,他可以花一点时间把它写下来,然后继续目前的工作。他后来发现不感兴趣的测试将从列表中删除

当列表上的所有项目都被划掉,并且你想不出要添加的新项目时,就会发生“完成”

如果您的测试也是以文档化为目标编写的,那么阅读已实现测试的列表以发现差距应该是直截了当的。Kevlin Henney关于MRU列表/闰年计算/堆栈的演讲显示了当问题非常小时,这可能是什么样子


当然,你也可以通过。。。测试代码。或者,当X以外的人第一次使用该代码时(假设故障导致错误)

这个问题更多地与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
    })
})
我会用简单的方法让这个测试通过

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“期望从代码中获得更多”

这是一个有争议的论点,Bob叔叔在其“干净的代码”中写到:在测试中包含多个断言是一个好的实践吗?我并不比参与这场辩论的人更好,但我可以注意到,定义函数的每一组数据都可以划分为“等价类”,因为开发人员编写的函数不是内射的,所以从同一等价类添加两个断言就像有一个,但约束更多

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
    })
})
description(“authServer.login()”,()=>{
它(“如果用户存在且密码有效,则应返回true”,()=>{
让结果=uut.login(“VALIDUSER”、“VALIDPASSWORD”)
期望(结果)是真的
期望(真的)是假的//