测试:参数输入验证

发布于 2024-10-20 05:28:23 字数 1220 浏览 2 评论 0原文

在下面的代码中,我想知道是否可以调整进行名称检查的测试。因为一旦我添加了检查 ID 不能为空的代码,我的前 3 个测试就会失败。

最后 3 个进行 id 测试的测试也是如此。我必须使用“foo”作为名称,否则这些测试也会失败。也不确定这样是否可以?

要测试的代码:

class Error

class Node
    constructor: (name, id) ->
        if not name?
            throw new Error('Name cannot be null')

        @name = name

        if not id?
            throw new Error('Id cannot be null')

        @id = id

window.Node = Node

规范:

node_spec = describe 'Node', () ->

    it 'should have the name foo', () ->
        expect( new Node('foo').name ).toEqual('foo')

    it 'should have the name bar', () ->
        expect( new Node('bar').name ).toEqual('bar')

    it 'should throw an error if the name is null', () ->
        expect( () -> new Node() ).toThrow()

    it 'should have an id of 0', () ->
        expect( new Node('foo', 0).id ).toEqual(0)

    it 'should have an of 1', () ->
        expect( new Node('foo', 1).id ).toEqual(1)

    it 'should throw an error if id is null', () ->
        expect( new Node('foo') ).toThrow()

window.node_spec = node_spec

更新: 我想一种解决方案是为 id 和 name 提供 getter 和 setter 方法,然后测试它们。

In the following code I was wondering if it's okay to adjust the tests that do the name checking. Because once I add the code that checks that the ID cannot be null my first 3 tests fail.

The same goes for the last 3 tests that do the id testing. I have to use 'foo' as a name cause otherwise those tests will fail too. Not sure if that's okay either?

Code to be tested:

class Error

class Node
    constructor: (name, id) ->
        if not name?
            throw new Error('Name cannot be null')

        @name = name

        if not id?
            throw new Error('Id cannot be null')

        @id = id

window.Node = Node

The spec:

node_spec = describe 'Node', () ->

    it 'should have the name foo', () ->
        expect( new Node('foo').name ).toEqual('foo')

    it 'should have the name bar', () ->
        expect( new Node('bar').name ).toEqual('bar')

    it 'should throw an error if the name is null', () ->
        expect( () -> new Node() ).toThrow()

    it 'should have an id of 0', () ->
        expect( new Node('foo', 0).id ).toEqual(0)

    it 'should have an of 1', () ->
        expect( new Node('foo', 1).id ).toEqual(1)

    it 'should throw an error if id is null', () ->
        expect( new Node('foo') ).toThrow()

window.node_spec = node_spec

Update:
I guess one solution is to have a getter and setter methods for both id and name and test those instead.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

愁以何悠 2024-10-27 05:28:23

在下面的 matyr 评论后进行编辑:我最初认为这是由于 new 运算符的奇怪之处,因为一些测试使用语法 new Foo ().bar。然而,在这些情况下,new 的行为正如 Pickels 所预期的那样。因此,尽管这个答案不是上述问题的解决方案,但为了后代的缘故,这里有一个回顾:

当您编写时,

new A().B

您正在引用新 B 属性一个实例。

但是,如果您编写

new A.B()

(或者只是 new AB - 如果 new 目标不存在,CoffeeScript 会在其末尾隐式添加括号),那么您将创建一个新的实例AB。这变得非常令人困惑——什么是 new A().B()?——因为 new 运算符有自己特殊的优先级规则。因此,我建议使用括号来澄清此类代码,例如

(new A).B
new (A.B)

这里有讨论关于试图在 CoffeeScript 中使这种行为更加直观,但经过一番努力后,确定“治疗方法比疾病更糟糕”。

Edited after matyr's comment below: I'd initially believed that this was due to the quirkiness of the new operator, since several of the tests use the syntax new Foo().bar. However, new behaves as Pickels had expected in those circumstances. So although this answer is not the solution to the stated problem, here's a review for posterity's sake:

When you write

new A().B

you're referencing the B property of a new A instance.

But if you write

new A.B()

(or just new A.B—CoffeeScript implicitly adds parentheses at the end of the new target if they're absent) then you're creating a new instance of A.B. This gets pretty confusing—what's new A().B()?—because the new operator has its own special precedence rules. So, I recommend using parentheses to clarify such code, e.g.

(new A).B
new (A.B)

There was discussion here about trying to make this behavior more intuitive in CoffeeScript, but after an energetic effort, it was determined that "the cure was worse than the disease."

原谅我要高飞 2024-10-27 05:28:23

让我再试一次:现在,您有三个测试失败。让我们弄清楚如何解决每个故障。

测试 #1

expect( new Node('foo').name ).toEqual('foo')

由于缺少 id,因此出现错误。我将保留该错误的测试,

expect( new Node('foo') ).toThrow()

并重写测试 #1 以声明一个合法的、无错误的 Node 实例,就像您对 id 测试行所做的那样

expect( new Node('foo', 1).name ).toEqual('foo')

:这没什么错。每次测试非错误行为时,都应该正确实例化;在本例中,这意味着传递名称和 ID。

测试#2

expect( new Node('bar').name ).toEqual('bar')

这与测试#1 基本相同。事实上,我想说你实际上在这里测试得太彻底了。您应该问的问题是:我是否有理由相信将 'bar' 作为名称而不是 'foo' 传递会产生不同的行为?我会说“不”。

因此,我要么直接删除 'bar' 测试,要么将 'bar' 替换为 '' (假设您希望允许空字符串作为名称),因为错误放置了 or 而不是 ?,或者 if name 而不是 if name?,可能会导致 '' 的行为与长度 > 的字符串不同0.

测试 #3

expect( () -> new Node() ).toThrow()

此测试失败,因为 () -> new Node() 定义了一个函数——一个永远不会运行的函数。我认为你的意思是只写 new Node()

其他想法

查看 Speks 文档,听起来首选样式是使用以下命令减少了重复的实例声明代码beforeEach。当然,当您测试构造函数本身时,这将不起作用,但您可能希望在将来的大部分测试中使用它。

这是测试套件的重写版本,其中包含所有这些建议,并将测试分为三种类型:创建异常的测试、预期正常行为的测试以及对象应该行为正常的测试但这是一种边缘情况:

node_spec = describe 'Node', () ->

  # exception tests
  it 'should throw an error if there are no arguments', () ->
      expect( new Node() ).toThrow()

  it 'should throw an error if there is only one argument', () ->
      expect( new Node('foo') ).toThrow()

  # normal tests
  node = new Node('foo', 1)

  it 'should have an id of 1', () ->
      expect( node.id ).toEqual(1)

  it 'should have the name foo', () ->
      expect( node.name ).toEqual('foo')

  # slightly unusual case of id = 0, name = '' (convertible to false)
  node = new Node('', 0)

  it 'should have an id of 0', () ->
      expect( node.id ).toEqual(0)

  it 'should have an empty string as its name', () ->
      expect( node.name ).toEqual('')

Let me try this again: Right now, you have three tests that are failing. Let's figure out how to address each failure.

Test #1

expect( new Node('foo').name ).toEqual('foo')

This is getting an error because id is missing. I would keep the test for that error,

expect( new Node('foo') ).toThrow()

and rewrite test #1 to declare a legit, error-free Node instance, just as you do with the id test lines:

expect( new Node('foo', 1).name ).toEqual('foo')

There's nothing wrong with that. Every time you're testing for non-error behavior, you should be instantiating properly; in this case, that means passing a name and an id.

Test #2

expect( new Node('bar').name ).toEqual('bar')

This is basically the same as test #1. In fact, I'd say you're actually testing too thoroughly here. The question you should be asking is: Do I have reason to believe that passing 'bar' as a name instead of 'foo' will produce a different behavior? I'd say "no."

So I'd either remove the 'bar' test outright, or replace 'bar' with '' (assuming that you want to allow empty strings as names), since a misplaced or instead of ?, or if name instead of if name?, could cause '' to behave differently than a string of length > 0.

Test #3

expect( () -> new Node() ).toThrow()

This test is failing because () -> new Node() defines a function—a function which is never run. I think you mean to write just new Node() instead.

Other thoughts

Looking at the Speks docs, it sounds like a preferred style is cut down on repeated instance declaration code using beforeEach. Of course, this won't work when you're testing the constructor itself, but you may want to use it for the bulk of your tests in the future.

Here's a rewritten version of your test suite incorporating all of these suggestions and dividing the tests into three types: Those where an exception is created, those where normal behavior is expected, and those where the object should behave properly but is an edge case:

node_spec = describe 'Node', () ->

  # exception tests
  it 'should throw an error if there are no arguments', () ->
      expect( new Node() ).toThrow()

  it 'should throw an error if there is only one argument', () ->
      expect( new Node('foo') ).toThrow()

  # normal tests
  node = new Node('foo', 1)

  it 'should have an id of 1', () ->
      expect( node.id ).toEqual(1)

  it 'should have the name foo', () ->
      expect( node.name ).toEqual('foo')

  # slightly unusual case of id = 0, name = '' (convertible to false)
  node = new Node('', 0)

  it 'should have an id of 0', () ->
      expect( node.id ).toEqual(0)

  it 'should have an empty string as its name', () ->
      expect( node.name ).toEqual('')
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文