简体   繁体   English

如何使用nosetest测试while循环(一次)(Python 2.7)

[英]How to test while-loop (once) with nosetest (Python 2.7)

I'm pretty new to this whole "programming thing" but at age 34 I thought that I'd like to learn the basics. 我对这整个“编程事物”都很陌生,但在34岁时,我认为我想学习基础知识。 I unfortunately don't know any python programmers. 我很遗憾不知道任何python程序员。 I'm learning programming due to personal interest (and more and more for the fun of it) but my "social habitat" is not "where the programmers roam" ;) . 我正在学习编程,因为个人兴趣(而且越来越多的乐趣)但我的“社交栖息地”不是“程序员漫游的地方”;)。 I'm almost finished with Zed Shaws "Learn Python the Hard Way" and for the first time I can't figure out a solution to a problem. 我差不多完成了Zed Shaws“艰难学习Python”,这是我第一次找不到问题的解决方案。 The last two days I didn't even stumble upon useful hints where to look when I repeatedly rephrased (and searched for) my question. 过去两天我甚至没有偶然发现有用的提示,当我反复改写(和搜寻)我的问题时,在哪里看。 So stackoverflow seems to be the right place. 所以stackoverflow似乎是正确的地方。 Btw.: I lack also the correct vocabular quite often so please don't hesitate to correct me :) . 顺便说一句:我经常缺乏正确的词汇,所以请不要犹豫,纠正我:)。 This may be one reason why I can't find an answer. 这可能是我找不到答案的原因之一。 I use Python 2.7 and nosetests. 我使用Python 2.7和nosetests。

How far I solved the problem (I think) in the steps I solved it: 我在解决它的步骤中解决了问题(我认为):

Function 1: 功能1:

def inp_1():
    s = raw_input(">>> ")
    return s

All tests import the following to be able to do the things below: 所有测试都导入以下内容以便能够执行以下操作:

from nose.tools import *
import sys
from StringIO import StringIO
from mock import *
import __builtin__
# and of course the module with the functions

Here is the test for inp_1: 以下是inp_1的测试:

import __builtin__
from mock import *

def test_inp_1():
    __builtin__.raw_input = Mock(return_value="foo")
    assert_equal(inp_1(), 'foo')

This function/test is ok. 这个功能/测试没问题。

Quite similar is the following function 2: 相似的是以下功能2:

def inp_2():
    s = raw_input(">>> ")
    if s == '1':
        return s
    else:
        print "wrong"

Test: 测试:

def test_inp_2():
    __builtin__.raw_input = Mock(return_value="1")
    assert_equal(inp_1(), '1')

    __builtin__.raw_input = Mock(return_value="foo")
    out = StringIO()
    sys.stdout = out
    inp_1()
    output = out.getvalue().strip()
    assert_equal(output, 'wrong')

This function/test is also ok. 这个功能/测试也没关系。

Please don't assume that I really know what is happening "behind the scenes" when I use all the stuff above. 当我使用上面的所有内容时,请不要认为我真的知道“幕后”发生了什么。 I have some layman-explanations how this is all functioning and why I get the results I want but I also have the feeling that these explanations may not be entirely true. 我有一些外行 - 解释这是如何运作的,以及为什么我得到我想要的结果,但我也觉得这些解释可能不完全正确。 It wouldn't be the first time that how I think sth. 这不是我第一次想到某事。 works turns out to be different after I've learned more. 在我学到更多东西后,工作结果却有所不同。 Especially everything with "__" confuses me and I'm scared to use it since I don't really understand what's going on. 尤其是“__”的一切让我感到困惑,我很害怕使用它,因为我真的不明白发生了什么。 Anyway, now I "just" want to add a while-loop to ask for input until it is correct: 无论如何,现在我“只是”想要添加一个while循环来请求输入,直到它是正确的:

def inp_3():
    while True:
        s = raw_input(">>> ")
        if s == '1':
            return s
        else:
            print "wrong"

The test for inp_3 I thought would be the same as for inp_2 . 我认为inp_3的测试与inp_2相同。 At least I am not getting error messages. 至少我没有收到错误消息。 But the output is the following: 但输出如下:

$ nosetests
......

     # <- Here I press ENTER to provoke a reaction
     # Nothing is happening though.

^C   # <- Keyboard interrupt (is this the correct word for it?)
----------------------------------------------------------------------
Ran 7 tests in 5.464s

OK
$ 

The other 7 tests are sth. 其他7项测试都是...... else (and ok). 别的(还可以)。 The test for inp_3 would be test nr. 对inp_3的测试将是测试nr。 8. The time is just the times passed until I press CTRL-C. 8.时间只是我按CTRL-C的时间。 I don't understand why I don't get error- or "test failed"-meassages but just an "ok". 我不明白为什么我没有得到错误 - 或“测试失败”-messages但只是一个“确定”。

So beside the fact that you may be able to point out bad syntax and other things that can be improved (I really would appreciate it, if you would do this), my question is: 除此之外,您可以指出错误的语法和其他可以改进的事情(我真的很感激,如果你这样做的话),我的问题是:

How can I test and abort while-loops with nosetest? 如何使用nosetest测试和中止while循环?

So, the problem here is when you call inp_3 in test for second time, while mocking raw_input with Mock(return_value="foo") . 所以,这里的问题是你第二次在test中调用inp_3,同时用Mock(return_value="foo") raw_input。 Your inp_3 function runs infinite loop ( while True ) , and you're not interrupting it in any way except for if s == '1' condition. 你的inp_3函数运行无限循环( while True ),你不会以任何方式打断它,除非是if s == '1'条件。 So with Mock(return_value="foo") that condition is never satisfied, and you loop keeps running until you interrupt it with outer means (Ctrl + C in your example). 因此,对于Mock(return_value="foo") ,该条件永远不会满足,并且循环继续运行,直到您使用外部方式(在您的示例中为Ctrl + C)中断它。 If it's intentional behavior, then How to limit execution time of a function call in Python will help you to limit execution time of inp_3 in test. 如果它是故意行为,那么如何限制Python中函数调用的执行时间将帮助您限制inp_3在测试中的执行时间。 However, in cases of input like in your example, developers often implement a limit to how many input attempts user have. 但是,在您的示例中输入的情况下,开发人员通常会对用户拥有的输入尝试次数实施限制。 You can do it with using variable to count attempts and when it reaches max, loop should be stopped. 您可以使用变量来计算尝试次数,当它达到最大值时,应该停止循环。

def inp_3():
    max_attempts = 5
    attempts = 0
    while True:
        s = raw_input(">>> ")
        attempts += 1 # this is equal to "attempts = attempts + 1"
        if s == '1':
            return s
        else:
            print "wrong"
            if attempts == max_attempts:
                print "Max attempts used, stopping."
                break # this is used to stop loop execution
                # and go to next instruction after loop block

    print "Stopped."

Also, to learn python I can recommend book "Learning Python" by Mark Lutz. 另外,为了学习python我可以推荐Mark Lutz的书“学习Python”。 It greatly explains basics of python. 它极大地解释了python的基础知识。

UPDATE : 更新

I couldn't find a way to mock python's True (or a builtin .True) (and yea, that sounds a bit crazy), looks like python didn't (and won't) allow me to do this. 我找不到一种方法来模拟python的True(或内置的 .True)(是的,这听起来有点疯狂),看起来像python没有(也不会)允许我这样做。 However, to achieve exactly what you desire, to run infinite loop once, you can use a little hack. 但是,为了达到你想要的效果,运行一次无限循环,你可以使用一点点黑客。

Define a function to return True 定义一个返回True的函数

def true_func():
    return True

, use it in while loop ,在while循环中使用它

while true_func():

and then mock it in test with such logic: 然后使用这样的逻辑在测试中模拟它:

def true_once():
    yield True
    yield False


class MockTrueFunc(object):
    def __init__(self):
        self.gen = true_once()

    def __call__(self):
        return self.gen.next()

Then in test: 然后在测试中:

true_func = MockTrueFunc()

With this your loop will run only once. 这样你的循环只会运行一次。 However, this construction uses a few advanced python tricks, like generators, "__" methods etc. So use it carefully. 但是,这种结构使用了一些高级的python技巧,比如生成器,“__”方法等。所以要小心使用它。

But anyway, generally infinite loops considered to be bad design solutions. 但无论如何,通常无限循环被认为是糟糕的设计解决方案。 Better to not getting used to it :). 最好不要习惯它:)。

It's always important to remind me that infinite loops are bad. 提醒我无限循环是不好的,这一点很重要。 So thank you for that and even more so for the short example how to make it better. 所以,非常感谢你,对于简短的例子,如何让它变得更好。 I will do that whenever possible. 我会尽可能地做到这一点。

However, in the actual program the infinite loop is how I'd like to do it this time. 但是,在实际程序中,无限循环是我这次想要的方式。 The code here is just the simplified problem. 这里的代码只是简化的问题。 I very much appreciate your idea with the modified "true function". 我非常感谢您对修改后的“真实功能”的想法。 I never would have thought about that and thus I learned a new "method" how tackle programming problems :) . 我从来没有想过这个,因此我学会了一种新的“方法”来解决编程问题:)。 It is still not the way I would like to do it this time, but this was the so important clue I needed to solve my problem with existing methods. 这次仍然不是我想做的方式,但这是我需要用现有方法解决问题的重要线索。 I never would have thought about returning a different value the 2nd time I call the same method. 我第二次调用相同的方法时,我从未考虑过返回不同的值。 It's so simple and brilliant it's astonishing me :). 它是如此简单和辉煌,令我惊讶:)。

The mock-module has some features that allows a different value to be returned each time the mocked method is called - side effect . 模拟模块具有一些功能,允许每次调用模拟方法时返回不同的值 - 副作用

side_effect can also be set to […] an iterable. side_effect也可以设置为可迭代的。 [when] your mock is going to be called several times, and you want each call to return a different value. [当]你的模拟将被多次调用,并且你希望每个调用返回一个不同的值。 When you set side_effect to an iterable every call to the mock returns the next value from the iterable: 当你将side_effect设置为iterable时,每次调用mock都会返回iterable中的下一个值:

The while-loop HAS an "exit" (is this the correct term for it?). while循环有一个“退出”(这是它的正确用语吗?)。 It just needs the '1' as input. 它只需要'1'作为输入。 I will use this to exit the loop. 我将用它来退出循环。

def test_inp_3():
    # Test if input is correct
    __builtin__.raw_input = Mock(return_value="1")
    assert_equal(inp_1(), '1')

    # Test if output is correct if input is correct two times.
    # The third time the input is corrct to exit the loop.
    __builtin__.raw_input = Mock(side_effect=['foo', 'bar', '1'])
    out = StringIO()
    sys.stdout = out
    inp_3()
    output = out.getvalue().strip()

    # Make sure to compare as many times as the loop 
    # is "used".
    assert_equal(output, 'wrong\nwrong')

Now the test runs and returns "ok" or an error eg if the first input already exits the loop. 现在测试运行并返回“ok”或错误,例如,如果第一个输入已经退出循环。

Thank you very much again for the help. 再次感谢你的帮助。 That made my day :) 这让我的一天:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM