基於碼雲開展程序設計教學的自動判分方法和代碼框架?

1. 目的

  • 學生基於碼雲提交程序設計做業;
  • 教師編寫檢查器,自動對全部人的做業進行判分;

2. 方法

下文中的代碼用於說明方法思想,但存在少許 Bug,懶得同步更新了。查找最新代碼,請移步碼雲【連接】。

2.1 做業提交要求

  1. 教師創建一個空項目,學生在該項目創建本身的分支(分支名 SEXXX,XXX 爲學號後三位),fork該項目到本地;
    • 引用自集美大學計算機鄭如濱的教學博客:『老師佈置程序項目類做業的時候,即便再三強調要按照規範來創建項目目錄結構。然而最終提交結果依然不盡如人意。每一個人彷佛都有本身的一套項目結構,而且這個結構一般是慘不忍睹的,好比一包流,全部代碼均放到一個包中。教師徹底能夠規劃好一個項目的標準目錄結構,而後讓學生Fork或clone下來,這樣就無痛的規範了全部學生的項目目錄結構。實際上這也是業界流行的一種方式。學生能夠參考集美大學-鄭如濱 老師的這個專門用於Java教學的一個項目OnlineShop,該項目包含一個可供參考的標準項目目錄結構。』
  2. 學生將完成的程序設計做業 push 到遠端本身對應的分支;
  3. 學生完成的程序做業要求知足必定的接口規範:如指定的文件名、函數名、輸出輸入接口等。

2.2 班級做業檢查框架: CheckFramework.sh

  • 只須要學生的分支命名規則不變,每次做業的 CheckFramework不須要修改
  1. 思路html

  2. 代碼git

#!/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 "\033[1;31m $0 \033[m\033[1;32m gitRepo_url\033[m.";
  echo "Such as:";
  echo "\033[1;31m $0\033[m\033[1;32m  https://gitee.com/se16/HelloWorld.git \033[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 \033[1;31m$RepoName\033[m.";

if [ -d $RepoName ]; then
    echo "deleting the directory named $RepoName";
    rm -rf $RepoName;   # debug #
fi
# clone the Repository.
echo -e "Cloning the Repository: \033[1;31m$1\033[m.";
git clone $1;    # 第一次

# 2.1 check if the repository($2) was correctly cloned.

if [ ! -d $RepoName ]; then
    # incorrect repository!
    echo "Cloning repository ${1##*/} \033[1;31mfailed\033[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 "\n-e NO.\033[1;31m$count\033[m. Reviewing homeworks of student NO. \033[1;32m$bra ...\033[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 "\nFinished";

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. 思路shell

  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 " \033[1;31m $0 \033[m\033[1;32m filename\033[m.";
  echo "eg. \033[1;31m $0\033[m\033[1;32m  HelloWord.c \033[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 \033[1;32m$1\033[m does\033[1;31m not exist\033[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
  • 還能夠有其餘審查項目,須要老師(助教)本身編寫檢查器,好比能夠:ide

      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
                       |-- \toos\--
                                       |-- \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 持續集成的方案,設計觸發器的,感受有點複雜,設置了幾回,跑不起來,如有誰搞通了,最好也寫篇博客;
相關文章
相關標籤/搜索