代码通过手动测试,但单元测试失败,可能吗?

时间:2016-02-24 12:12:50

标签: python class unit-testing

我在自学在线python课程编程3周。目标是扩展一个基本的BankAccount类,您可以通过子类MinimumBalanceAccount尽可能多地撤销,其中拒绝过多的withdrwals。以下是我到目前为止的情况:

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)
$ 

我做错了什么?

1 个答案:

答案 0 :(得分:4)

unittest返回:

..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"。这里的继承没有错,但是当你覆盖一个方法时,你不会从该方法的超类实现继承(除非你把它称为explicitey)。

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 {1}}但也适用于开场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 ......