作业三:结对项目

这个作业属于哪个课程 软件工程
这个作业要求在哪里 结对项目
这个作业的目标 两人合作,根据需求完成一个四则运算题目生成器的开发
本次作业的仓库地址 项目地址
项目成员 学号
陈靖凯 3122004856
刘曦烨 3122004746

1. 各模块开发消耗时间(PSP表格)

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 10 5
· Estimate · 估计这个任务需要多少时间 360 240
Development 开发 335 315
· Analysis · 需求分析 (包括学习新技术) 10 5
· Design Spec · 生成设计文档 15 10
· Design Review · 设计复审 5 5
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 5 5
· Design · 具体设计 30 30
· Coding · 具体编码 180 210
· Code Review · 代码复审 30 40
· Test · 测试(自我测试,修改代码,提交修改) 10 10
Reporting 报告 60 50
· Test Repor · 测试报告 35 20
· Size Measurement · 计算工作量 10 5
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 15 15
· 合计 405 370

2. 设计过程

根据需求的描述,可以发现项目需要实现的功能大体可以分为三种

  • 文件的写入
  • 题目的生成
  • 答案的计算
    对于三个不同的功能,可以设计三个类分别实现对应的功能,在项目中,以上三个类分别为FileManager类、QuestionGenerator类和QuestionCalculator类,并通过主程序调用这些类实现完整的功能
    类中各函数调用关系:
    QuestionGenerator类

    QuestionCalculator类

    FileManager类

    主程序main与各个类调用关系

3. 效能分析

由于项目开发使用的语言为python,故使用了cProfile库进行性能的分析,通过生成一万个题目,并输出关键函数的各种信息统计如下:

对应列的运行分析信息解释如下:

列表标题 解释
ncalls 函数调用次数
tottime 在给定函数中花费的总时间(不包括调用子函数的时间)
percall tottime除以ncalls的商
cumtime 函数和所有子函数中花费的累积时间(从调用到退出)
percall cumtime除以原始调用次数的商
filename:lineno(function) 提供每个函数的各自信息
综合以上信息发现,消耗时间最长的是生成题目的函数

显然,即使是生成一万个不重复的题目,运行耗时都极低,说明代码运行效率极高,无需优化

4. 关键代码及解释

  • 生成题目表达式的关键函数:
    def generate_operation(self,max_operand):
     operators = ['+', '-', '×', '÷']
     num_operators = random.randint(1, 3)
     expression = str(random.randint(1, max_operand))

     for _ in range(num_operators):
        operator = random.choice(operators)
        operand = random.randint(1, max_operand)

        if operator == '÷':
            # 生成真分数
            numerator = random.randint(1, operand - 1) if operand > 1 else 1
            fraction = Fraction(numerator, operand)
            expression += f" {operator} {fraction}"
        else:
            if operator == '-':
                # 避免生成负数
                operand = random.randint(1, int(expression.split()[-1]))
            expression += f" {operator} {operand}"

        return expression
  • 计算结果的函数:
 def evaluate_expression(expression):
        try:
            # 将真分数转换为浮点数进行计算
            expression = expression.replace('×', '*')
            result = eval(expression.replace('÷', '/'))
            # 如果结果是浮点数,将其转换为真分数
            if isinstance(result, float):
                return str(Fraction(result).limit_denominator())
            return str(result)
        except ZeroDivisionError:
            return "Undefined"

5. 测试过程

5.1 单元测试

通过使用pytest库进行单元测试,编写单元测试代码如下:

import pytest
from QuestionGenerator import QuestionGenerator
from QuestionCalculator import *

@pytest.fixture
def question_generator():
    return QuestionGenerator()
def test_generate_operation(question_generator):
    max_operand = 10
    for _ in range(10):  # 多次测试以确保随机性
        operation = question_generator.generate_operation(max_operand)
        assert isinstance(operation, str)
       
def test_generate_math_questions(question_generator):
    num_questions = 5
    max_operand = 10
    questions = question_generator.generate_math_questions(num_questions, max_operand)
    assert len(questions) == num_questions
    for question in questions:
        assert isinstance(question, str)

@pytest.fixture
def calculator():
    return Calculator()
def test_evaluate_expression_fraction_addition(calculator):
    expression = "1/2 + 1/3"
    result = calculator.evaluate_expression(expression)
    assert result == "5/6"
def test_evaluate_expression_integer_division(calculator):
    expression = "10 ÷ 2"
    result = calculator.evaluate_expression(expression)
    assert result == "5"
def test_evaluate_expression_divide_by_zero(calculator):
    expression = "5 ÷ 0"
    result = calculator.evaluate_expression(expression)
    assert result == "Undefined"
def test_calculate_answers(calculator):
    questions = ["2 + 2", "3 × 4", "10 ÷ 5"]
    expected_answers = ["4", "12", "2"]
    answers = calculator.calculate_answers(questions)
    assert answers == expected_answers

if __name__ == "__main__":
    pytest.main()

测试结果:

5.2 命令行运行测试

输入指令

运行后生成的文件内容

6. 项目小结

本项目作为我们再次一起合作开发的项目,因为我们同时也都是一个工作室的成员,有过一起开发项目的经历
此次合作开发的经历给我们带来的收获有:

  • 分工安排上更加明确
  • 对项目管理软件使用也比第一次合作开发更加熟练,目前我们都已经熟练掌握了git的基本指令,像什么git clone、git pull、git push之类的基础指令
  • 对于项目的需求分析能力也大幅提升,可以更好地将需求转化为要实现的功能
posted @ 2024-03-25 21:53  hnbxs  阅读(13)  评论(0编辑  收藏  举报