三层各自的红绿
(每道题开头都有同一段:上面那套被测系统、unittest 和 mock,以及 eng_07 的静音 run(*cases)——交回「跑了几条/挂了几条/出错几条」。)
贯穿全条的被测系统(四段流水线):
parse(line) "苹果 3 2.5" → ("苹果", 3, 2.5);不是三段就 raise ValueError
subtotal / discount 数量×单价;合计满 100 打九折
Store add(名, 数量, 单价);total() = discount(各小计之和)
report(store, rate) 每样一行「名 数量 小计」,末行「合计 X 约 Y 外币」(Y = X / 汇率)
fetch_rate() 真的去连汇率服务——本地没网,一调就 ConnectionError
handle(lines, get_rate) 整条流水线:parse 每行 → Store → report(get_rate())给三层各一条测试,跑在正确的 discount 和一个改坏的 discount(阈值写成 >100)上,看各层红绿:
import io, unittest
from unittest import mock
def parse(line):
w = line.split()
if len(w) != 3:
raise ValueError("格式不对:" + line)
return w[0], int(w[1]), float(w[2])
def subtotal(qty, price):
return qty * price
def discount(amount):
return amount * 0.9 if amount >= 100 else amount
class Store:
def __init__(self):
self.items = []
def add(self, name, qty, price):
self.items.append((name, qty, price))
def total(self):
return discount(sum(subtotal(q, p) for _, q, p in self.items))
def fmt(x):
return ("%.2f" % x).rstrip("0").rstrip(".")
def report(store, rate):
lines = [n + " " + str(q) + " " + fmt(subtotal(q, p)) for n, q, p in store.items]
t = store.total()
lines.append("合计 " + fmt(t) + " 约 " + fmt(t / rate) + " 外币")
return "\n".join(lines)
def fetch_rate():
raise ConnectionError("没有网络:汇率服务连不上")
def handle(lines, get_rate=fetch_rate):
store = Store()
for line in lines:
n, q, p = parse(line)
store.add(n, q, p)
return report(store, get_rate())
def run(*cases):
suite = unittest.TestSuite()
for c in cases:
suite.addTests(unittest.defaultTestLoader.loadTestsFromTestCase(c))
r = unittest.TextTestRunner(stream=io.StringIO()).run(suite)
return str(r.testsRun) + "/" + str(len(r.failures)) + "/" + str(len(r.errors))
SAMPLE = ["苹果 3 2.5", "西瓜 2 30", "米 10 4.2"]
def run_layers(disc):
global discount
old = discount
discount = disc
class U(unittest.TestCase):
def test_parse(self):
self.assertEqual(parse("苹果 3 2.5"), ("苹果", 3, 2.5))
class I(unittest.TestCase):
def test_total(self):
s = Store()
s.add("米", 10, 10)
self.assertAlmostEqual(s.total(), 90)
class E(unittest.TestCase):
def test_full(self):
self.assertTrue(handle(["米 10 10"], lambda: 1.0).endswith("合计 90 约 90 外币"))
r = run(U) + "|" + run(I) + "|" + run(E)
discount = old
return r
print(run_layers(discount) + "//" + run_layers(lambda a: a * 0.9 if a > 100 else a))
全部评论