0

I'm creating class which behaves like list(), but you can add strings to it and these strings will be splitted by spaces on words and these words will be added to the class instance. Same with substraction: substraction removes words from class instance (if any).

I faced with strange behavior in nose tests: behavior changes when I'm simply changing order of assertions.

Here is test:

from nose.tools import *

def test_isub_str(self):
    u = params()

    u += "1 2 3 4"
    u -= "2 3"

    ok_("1" in u, u)
    ok_("2" not in u, u)
    ok_("3" not in u, u)
    ok_("4" in u, u)

This test fails with following output:

Traceback (most recent call last):
  File "tests.py", line 71, in test_isub_str
    ok_("4" in u, u)
    assert expr, msg
AssertionError: 1 4

Strange, the "u" is dumped as "1 4", but "4" wasn't found in "u" during assertion testing. And the most interesting happens when I change the order of assertions to following:

ok_("1" in u, u)
ok_("4" in u, u)
ok_("2" not in u, u)
ok_("3" not in u, u)

Then tests are passing OK and this is correct, expected behavior. It looks like "not in" statement changes behavior of following "in" statements. I'm surprized.

Finally, here is my class:

class params():
    def __init__(self):
        self.index = 0 # iterator index
        self.values = [] # list of stored values

    def __iadd__(self, addvalues):
        if isinstance(addvalues, str):
            addvalues = addvalues.split(" ")
        # add all values to this instance if they are list() or params()
        # and not exist in current instance
        if isinstance(addvalues, params) or isinstance(addvalues, list):
            for value in addvalues:
                if isinstance(value, str) and value not in self.values:
                    self.values.append(value)
                else:
                    raise TypeError
            return self
        else:
            raise TypeError

    def __isub__(self, subvalues):
        if isinstance(subvalues, str):
            subvalues = subvalues.split(" ")
        # substract all values from this instance if they are list() or params()
        # and existing in current instance
        if isinstance(subvalues, params) or isinstance(subvalues, list):
            for value in subvalues:
                if isinstance(value, str) and value in self.values:
                    self.values.remove(value)
                else:
                    raise TypeError
            return self
        else:
            raise TypeError

    def __iter__(self):
        return self

    def next(self):
        if self.index >= len(self.values):
            raise StopIteration
        else:
            self.index += 1
            return self.values[self.index - 1]

    def __str__(self):
        return " ".join(self.values)

So question is: why such strange behavior happens? I missed something in iterator functionality? Or this nosetests bug?

4

1 回答 1

0

不,这不是鼻子测试错误,我认为当你这样做时

ok_("1" in u, u)

u.index 为 1,当你这样做时:

ok_("2" not in u, u)
ok_("3" not in u, u)

u.index 是 2。当你这样做时

ok_("4" in u, u)

u.index 仍然是 2,并且您的“下一个”方法会引发 StopIteration,因为 2 >= len(self.values)。

在您的第二种情况下,当您执行以下操作时 u.index 仍然为 1:

ok_("4" in u, u)
于 2012-08-05T16:32:39.510 回答