【问题标题】:Code passes manual tests, but fails on unit test, Possible? [closed]代码通过手动测试,但在单元测试中失败,可能吗? [关闭]
【发布时间】:2016-06-06 17:28:08
【问题描述】:

我已经为自学在线 Python 课程编程了 3 周。目标是扩展一个基本的 BankAccount 类,您可以通过子类 MinimumBalanceAccount 尽可能多地取款,其中过多的取款被拒绝。这是我目前所拥有的:

class BankAccount:
    def __init__(self, balance):
        self.balance = balance

    def deposit(self, amount):
        self.balance += amount
        return self.balance

    def withdraw(self, amount):
        if(amount > self.balance):
            print "invalid transaction."
        else:
            self.balance -= amount
            return self.balance   

class MinimumBalanceAccount(BankAccount):
    def __init__(self, minimum_balance):
        BankAccount.__init__(self, self.balance)
        self.minimum_balance = minimum_balance

    def withdraw(self, amount):
        if(self.balance - amount < self.minimum_balance):
            print "Minimum balance exceeded."
        else:
            self.balance -= amount
            return self.balance

由于在线课程具有在线单元测试功能,我从练习定义中编写了以下单元测试:

import unittest

class AccountBalanceTestCases(unittest.TestCase):
    def setUp(self):
       self.my_account = BankAccount(90)
    # omitting tests that pass ok...
    def test_invalid_operation(self):
       self.assertEqual(self.my_account.withdraw(1000), "invalid transaction", msg='Invalid transaction')

unittest.main(verbosity=2)

测试有望通过,但是:

$ python bank2.py
test_invalid_operation (__main__.AccountBalanceTestCases) ... invalid transaction.
FAIL

======================================================================
FAIL: test_invalid_operation (__main__.AccountBalanceTestCases)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "bank2.py", line 36, in test_invalid_operation
    self.assertEqual(self.my_account.withdraw(1000), "invalid transaction", msg='Invalid transaction')
AssertionError: Invalid transaction

----------------------------------------------------------------------
Ran 1 test in 0.001s

FAILED (failures=1)
$ 

我做错了什么?

【问题讨论】:

  • 究竟是什么没有通过?
  • 请注意,一个明显的错误是您的提款方法不会返回无效的交易消息,因为指令和您的测试状态都会打印出来。
  • 它告诉我运行你的代码时出错。
  • 不,它没有。运行单元测试的重点是它会在断言失败时为您提供消息。那么,哪些断言失败了?你得到了什么错误?是什么让您认为单元测试是“错误的”?
  • 所以我猜测您正在使用某种在线标记工具。这一切都很好,但是您需要先在本地运行您的代码;如果你这样做了,你会看到失败测试的细节,如 flaschbier 所示。

标签: python class unit-testing


【解决方案1】:

单元测试返回:

..invalid transaction.
F..
======================================================================
FAIL: test_invalid_operation (__main__.AccountBalanceTestCases)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "bank.py", line 48, in test_invalid_operation
    self.assertEqual(self.my_account.withdraw(1000), "invalid transaction", msg='Invalid transaction')
AssertionError: Invalid transaction

----------------------------------------------------------------------
Ran 5 tests in 0.001s

FAILED (failures=1)
$ 

第一句话是马上进入单元测试的拥抱。但是,unittest.Testcase 不应该 print 任何东西,因为这会将垃圾推入 unittest 输出中。

在这种情况下,我们从 self.my_account.withdraw(1000) 不返回 "invalid transaction" 的异常中读取。确实:

def withdraw(self, amount):
    if(self.balance - amount < self.minimum_balance):
        print "Minimum balance exceeded."
    else:
        self.balance -= amount
        return self.balance

withdraw 在特殊情况下不返回任何内容。所以你的测试代码没问题,它已经很好地为你服务了:)

要通过测试,withdraw 方法必须返回字符串 "invalid transaction"。这里的继承没有错,但是当你覆盖一个方法时,你并没有从那个方法的超类实现继承(除非你显式地调用它)。

def withdraw(self, amount):
    if(self.balance - amount < self.minimum_balance):
        print "Minimum balance exceeded."
        return "invalid transaction"
    else:
        self.balance -= amount
        return self.balance

关于提问的一般评论:当代码正确缩进时以及当我们立即遇到异常时,这将有很大帮助;)

更新更深入地探讨继承问题:当您希望 MinimumBalanceAccount 成为真正的 BankAccount 时,您不仅要关心 minimum_balance,还要关心开头balance 因为这是超类需要的部分:

class MinimumBalanceAccount(BankAccount):
    def __init__(self, balance, minimum_balance):
        BankAccount.__init__(self, balance)
        self.minimum_balance = minimum_balance
    def withdraw(self, amount):
        ...

当然,我做了这个测试驱动:

class MBATest(unittest.TestCase):
  def setUp(self):
    self.my_mba = MinimumBalanceAccount(90, 10)
  def test_mba_withdraw(self):
    # put in one test to be sure about the oder of execution ;)
    self.assertEqual(self.my_mba.withdraw(10), 80)
    self.assertEqual(self.my_mba.withdraw(100), "invalid transaction")

这个会通过的。因为我喜欢冗长,所以我使用unittest.main(verbosity=2) 并最终得到:

$ python bank.py
test_balance (__main__.AccountBalanceTestCases) ... ok
test_deposit (__main__.AccountBalanceTestCases) ... ok
test_invalid_operation (__main__.AccountBalanceTestCases) ... ok
test_sub_class (__main__.AccountBalanceTestCases) ... ok
test_withdraw (__main__.AccountBalanceTestCases) ... ok
test_mba_withdraw (__main__.MBATest) ... ok
----------------------------------------------------------------------
Ran 6 tests in 0.000s
OK
$

也许你应该通过this question 工作,如果你喜欢它,也可以通过this one...

【讨论】:

  • 感谢您的反馈,并原谅我没有缩进的愚蠢错误。甚至还没有阅读有关异常的信息。这个问题是否需要我实现子类,或者我可以简单地使用 pass?有关更正我的代码以反映所要求的内容的任何提示。
  • 没关系。我们几乎都是学生;)更新了解决继承问题的答案。
  • 谢谢,通过删除超类中的withdraw方法更改代码并添加第三个选项: if(amount > self.balance): print "invalid transaction."在子类的withdraw方法中。所有手动测试都在进行,但单元文本没有:
  • 如何将余额变量放入最小余额账户构造函数中,然后传递给超类构造函数?
  • 用一些想法更新了答案...
猜你喜欢
  • 2010-11-19
  • 1970-01-01
  • 2017-10-12
  • 2017-08-15
  • 2019-12-07
  • 2016-06-25
  • 1970-01-01
  • 1970-01-01
  • 2010-09-09
相关资源
最近更新 更多