• 基于码云开展程序设计教学的自动判分方法和代码框架?


    1. 目的

    • 学生基于码云提交程序设计作业;
    • 教师编写检查器,自动对所有人的作业进行判分;

    2. 方法

    下文中的代码用于说明方法思想,但存在少量 Bug,懒得同步更新了。查找最新代码,请移步码云【链接】。

    2.1 作业提交要求

    1. 教师建立一个空项目,学生在该项目建立自己的分支(分支名 SEXXX,XXX 为学号后三位),fork该项目到本地;
      • 引用自集美大学计算机郑如滨的教学博客:『老师布置程序项目类作业的时候,即使再三强调要按照规范来建立项目目录结构。然而最终提交结果依然不尽如人意。每个人似乎都有自己的一套项目结构,并且这个结构通常是惨不忍睹的,比如一包流,所有代码均放到一个包中。教师完全可以规划好一个项目的标准目录结构,然后让学生Fork或clone下来,这样就无痛的规范了所有学生的项目目录结构。实际上这也是业界流行的一种方式。学生可以参考集美大学-郑如滨 老师的这个专门用于Java教学的一个项目OnlineShop,该项目包含一个可供参考的标准项目目录结构。』
    2. 学生将完成的程序设计作业 push 到远端自己对应的分支;
    3. 学生完成的程序作业要求满足一定的接口规范:如指定的文件名、函数名、输出输入接口等。

    2.2 班级作业检查框架: CheckFramework.sh

    • 只需要学生的分支命名规则不变,每次作业的 CheckFramework不需要修改
    1. 思路

    2. 代码

    #!/bin/sh
    # Filename: CheckFramework.sh
    #
    # Usage checkRepo.sh git_repo_url
    #
    # Algorithm:
    #   1.  clone git_repo to local directory
    #   2.  checkout to each branch (of every student)
    #   3.  testing and evaluating each program written by students.
    #   4.  return result  (csv 格式)
    #
    # Input: git_repo_url
    # output: result.csv   
    #
    ######################################################################       
    
    # 0. Global variants
    ResultFile="result.csv" ;          # 返回每个学生的成绩
    WorkSpace=`pwd`;
    export WorkSpace;                      # 输出当前工作路径:WorkSpace
    
    # 1. check repo_url
    if [ $# -lt 1 ]; then
      echo "Usage:";
      echo "33[1;31m $0 33[m33[1;32m gitRepo_url33[m.";
      echo "Such as:";
      echo "33[1;31m $033[m33[1;32m  https://gitee.com/se16/HelloWorld.git 33[m";
      exit;
    fi
    
    # 2. git clone repository $1
    # 2.0 if the repository have been cloned before, remove (delete) the repository and re-clone it.
    RepoName=`echo ${1##*/} | cut -d "." -f 1`;
    echo "the Repository name is 33[1;31m$RepoName33[m.";
    
    if [ -d $RepoName ]; then
        echo "deleting the directory named $RepoName";
        rm -rf $RepoName;   # debug #
    fi
    # clone the Repository.
    echo -e "Cloning the Repository: 33[1;31m$133[m.";
    git clone $1;    # 第一次
    
    # 2.1 check if the repository($2) was correctly cloned.
    
    if [ ! -d $RepoName ]; then
        # incorrect repository!
        echo "Cloning repository ${1##*/} 33[1;31mfailed33[m. Check it's url, please!";
        exit;
    fi
        
    # 2.2 successfully cloned the repository. Now change working directory to sub-directory named $RepoName
    #     step1 : checkout to $bra, 
    #     step2 : and check the homeworks one by one, give evaluation score of each homework.
    #             (use an function outsides) 
    #     step3 : output result.
    
    # 2.2.0 delete previous result.csv
    if [[ -f $ResultFile ]]; then
        #statements 
        rm result.csv;
    fi
    
    echo -e "Processing homeworks in each branch named SEXXX";
    
    cd $WorkSpace/$RepoName;
    
    # 列举本地分支,筛选学生建立的『SEXXX』分支,删除当前分支前的星号 "*"" ,及空格
    git branch --all | cut -d "/" -f 3| grep -ai 'se' | sed 's/[* ]//g'> $WorkSpace/branches.txt;
    
    count=0;
    
    while read bra; do
        let count=count+1;
        # 2.2.1 checkout ; OK
        git checkout -q $bra;  #  -q --quiet          # suppress progress reporting
    
        # 2.2.2 run test script, and return a score of current branch(student). Dev
        echo "
    -e NO.33[1;31m$count33[m. Reviewing homeworks of student NO. 33[1;32m$bra ...33[m ";
    
        # call CheckersCaller : driver , and export TotalScore
            # echo $WorkSpace;
            source $WorkSpace/CheckersCaller.sh;
     
           # return score of current branch (student's work)
            score=$TotalScore;
          
            # 2.2.3 write score to a structure which records all students scores. OK
        echo "$bra,$score" >> $WorkSpace/$ResultFile
    done < $WorkSpace/branches.txt
    
    echo "
    Finished";
    

    2.3 作业的检查器: CheckersCaller.sh

    • 每次作业的 Checkers 不一样,需要独立设计
    • 对应地 CheckersCaller.sh 需要对 score 的汇总做微调 (包括:权重、汇总项目)
    1. 思路
    • 依次采用 命令 source Checker_i.sh ,调用不同的检查器;
    • 这些检查器 Checker_i.sh 输出 对应的检查项目得分 score_i
    • 对每一项检查赋予权重 wi, 对所有检查项目得分加权(wi),得到汇总得分 TotalScore
    • 输出TotalScore。(export TotalScore
    1. 代码
    #!/bin/sh
    # Filename: CheckersCaller.sh
    #
    # Usage: CheckersCaller.sh
    #
    # Algorithm:
    # 1.    call checkers which export a set of scores
    # 2.   summation:sum the scores to TotalScore
    # 3.   export TotalScore
    #
    # Input:Null
    # Output:TotalScore   -- summation of each score_i.
    #
    #####################################################       
    
    TotalScore=0
    
    # 1. 调用一组Checker_i.sh 脚本, 得到一组输出 score_i (单项得分)
    source $WorkSpace/Checker_1.sh  "*.c";
    let s1=score_1;
    
    source $WorkSpace/Checker_1.sh  "*.cpp";
    let s2=score_1;
    
    source $WorkSpace/Checker_1.sh  "*.py";
    let s3=score_1;
    
    # ...
    # source Checker_n.sh
    
    # 2. 汇总得分 (wi 为每一项的权重)
    # let TotalScore=score_1*w1+score_2*w2+...+score_n*wn
    let TotalScore=s1+s2+s3;
    
    echo "TotalScore : $TotalScore";
    
    # 3. 输出汇总分 TotalScore
    export TotalScore;
    
    

    2.4 作业的单项检查器: Checker_i.sh

    1. 思路

    2. 代码示例

    • 这里给出一个静态代码审查的示例。(Checker_1.sh)
    #!/bin/sh
    # Checker_1.sh
    #
    # Usage Checker_1.sh filename
    #
    # Algorithm :
    # 1.  check the file (SUT) existence
    # 2.  Review or test SUT, give an evaluation score (score)
    # 3.  export score_i  (score_i equals to evaluation result.)
    #
    # Input: filename  -- software under test(review)SUT
    # Output:score_i   -- export score_i
    #
    #################################################       
    # 0. Global variable for export
    score_1=0                   # here i=1
    
    # 1. checker_i Usage
    if [ $# -lt 1 ]; then
      echo "Usage:";
      echo " 33[1;31m $0 33[m33[1;32m filename33[m.";
      echo "eg. 33[1;31m $033[m33[1;32m  HelloWord.c 33[m";
      exit;
    fi
    
    # 2. Does file $1 exist?  s_temp is the evaluation
    full_filename="";
    full_filename=`find . -name $1`;
    
    #if [[ ! -f $1 ]]; then  # file does not exist
    if [[ ${#full_filename} == 0 ]]; then  # file does not exist
        echo "File 33[1;32m$133[m does33[1;31m not exist33[m!";
        s_temp=0;
    else
        # in this block, you can call other tools or write scripts for evaluating
            # call foreign tools or scripts             # return a score 
            # ......
            s_temp=`$WorkSpace/tools/sloccount/c_count $full_filename | sed -n '$p'`;   # sed -n  '$p'取最后一行数据
    
            echo "Lines of $full_filename  is $s_temp";
    fi
    
    # 3. export global variable
    let score_1=s_temp;
    export score_1
    
    
    • 还可以有其他审查项目,需要老师(助教)自己编写检查器,比如可以:

        1. 编译待测代码. 可编译,给一个评测分 s2
        1. 运行N 个测试用例,若通过测试数量 n,则 给出评测得分 s3= totalOfTesting * n/N

    2.5 系统文件组织结构及输出

    • 文件结构组织
        ..workspace --
                           |-- CheckFramework.sh
                           |-- CheckersCaller.sh
                           |-- Checker_1.sh
                           |-- Checker_2.sh
                           |--  .... ...
                           |-- Checker_n.sh
                           |-- 	oos--
                                           |-- sloccount .....   # 一组代码行计数工具, 这些工具供给 检查器 ``Checker_i.sh``使用
                                           |-- ********* .....   # 其他软件度量工具
                                           |--  .....                    # 
                           |-- RepositoriesName                    # clone 到本地的远程仓库
                           |-- result.csv                          # 检查得分,与分支名对应 (不同的学生对应不同的分支)
                           |-- branches.txt                        # 临时文件,存放学生分支 (不同的学生对应不同的分支,命名规则 SEXXX ,XXX 学号后三位
    
    
    • 输出 。 输出文件 result.csv

    3. 其他的思考

    3.1 本文的方法

    • 本文方法的需要老师自己编写检查器(Checker_i.sh),工作量有些大,本文对检查器的接口做了定义,具体检查内容需要老师自己定义。
    • 另外,对学生提交程序的接口有较严格的要求。建议老师先建立项目,定义好各类接口,学生 fork 该项目。

    3.2 其他方案

    • 是不是还可以借助 git push 机制,触发自动检查、评分的。 目前,不清楚
    • 本想利用 Jenkins 持续集成的方案,设计触发器的,感觉有点复杂,设置了几次,跑不起来,若有谁搞通了,最好也写篇博客;
  • 相关阅读:
    CocoaPods 中删除不需要的第三方
    真机测试是提示 的 iPhone is busy: Preparing debugger support for
    关于 Expression is not assignable 错误
    关于查询ios的app更新的历史版本记录
    ios开启双重认证之填坑式教学
    swift 有道 翻译文档(2 条件语句 循环语句)
    swift 有道 翻译文档(1 定义变量常量,数组字典)
    渐变UI
    cornerstone 使用
    cocoaPods安装
  • 原文地址:https://www.cnblogs.com/juking/p/9733978.html
Copyright © 2020-2023  润新知