歡迎來到軟件工程 😃
前言
本博客為完成個人項目所需的先導知識,題目不難,請認真對待 😃
注:本次實驗為附加作業,不做不扣分,做了有附加分
Part 0. 背景
阿超家里的孩子上小學一年級了,這個暑假老師給家長們布置了一個作業:家長每天要給孩子出一些合理的,但要有些難度的四則運算題目,並且家長要對孩子的作業打分記錄。
作為程序員的阿超心想,既然每天都需要出題,那何不做一個可以自動生成小學四則運算題目與解決題目的命令行 “軟件”呢。他把老師的話翻譯一下,就形成了這個軟件的需求:
-
程序接收一個命令行參數 n,然后隨機產生
n
道加減乘除(分別使用符號+-*/
來表示)練習題,每個數字在0
和100
之間,運算符在2
個 到3
個之間。 -
由於阿超的孩子才上一年級,並不知道分數。所以軟件所出的練習題在運算過程中不得出現非整數,比如不能出現
3÷5+2=2.6
這樣的算式。 -
練習題生成好后,將生成的
n
道練習題及其對應的正確答案輸出到一個文件subject.txt
中。 -
當程序接收的參數為4時,以下為一個輸出文件示例。
13+17-1=29 11*15-5=160 3+10+4-16=1 15÷5+3-2=4
這次阿超選擇使用他最拿手的 C++
語言來完成這樣的需求,工欲善其事必先利其器,第一步就需要先安裝一個好用的 IDE ,在這里我們推薦使用 Visual Studio 2017
。
Part 1. 配置環境
Visual Studio 2017 有着宇宙最強 IDE 的美稱,它對 C++ 的支持也很好,在本教程中,為簡化學員的開發難度,我們選擇使用 VS2017 社區版(社區版(Community)指的是可免費提供給單個開發人員,給予初學者及大部分程序員支持,可以無任何經濟負擔、合法地使用的版本。)
下面提供三種安裝方法:
-
官網下載:點擊下載鏈接,瀏覽器將自動開始下載
-
下載迅雷,輸入以下ed2k鏈接:
ed2k://|file|mu_visual_studio_community_2017_version_15.3_x86_x64_11100062.exe|1069960|5984B3CD547F9F213DE21EFE5887F08D|/
-
百度網盤:鏈接: https://pan.baidu.com/s/1jJXyRMA 密碼: ub6c
下載的文件只是一個引導安裝程序,下載完成后,雙擊運行,如果出現下面的 Visual Studio 提示:
則需要首先自行安裝版本較高的 .Net Framework
( .NET Framework 4.6 可以在這里下載到)如果沒有出現該提示,請忽略。
在點擊開 exe
文件后,一路繼續,可以看到如下的選擇界面。由於我們只需要 C++
庫,所以只需要勾選 【使用 C++
的桌面開發】即可。由於 VS
本身體積較大,推薦修改存儲位置,將其安裝在非系統盤目錄。
如果順利的話,過一大段時間 VS2017 就會下載好相應文件,此時會提示要求重啟,此時按照指示重啟即可。
安裝成功后,首次使用 VS 2017 還需要對其進行簡單的配置,包括開發環境的主題風格。如果要求登錄的話,可以使用你的outlook賬號登錄,或者可以選擇忽略。
這里開發設置選擇 C++即可,主題推薦深色主題。
Part 2. 克隆項目
阿超的項目放在了當下最流行的源代碼管理平台 Github
上,倉庫地址。那么,我們如何在阿超項目的基礎上進行開發呢?
-
在 https://github.com/join 這個網址處申請注冊一個 Github 賬號,申請成功后可在 https://github.com/login 處利用剛剛注冊的賬號進行登錄,才能開始在 Github 上進行開發。
-
成功登錄后,輸入阿超倉庫的網址 https://github.com/ChildishChange/Calculator ,點擊右上角的
Fork
,將阿超的四則運算庫拷貝到自己的同名倉庫中,如下圖所示: -
拷貝成功后,可以看到自己已經擁有了一個同名倉庫。這里我們登錄的是 buaase 的賬號:
-
在自己的電腦上安裝 Git 軟件,Git 的安裝教程在這里。在自己拷貝項目的主頁的綠色按鈕處可以找到一個可克隆的項目地址,下面是一個示例:
-
在 我的電腦 中任意找一個目錄,打開 Git 命令行軟件(Windows上可在空白處右鍵打開 Git Bash ),輸入
git clone <clone url>
,其中<clone url>
即我們剛剛復制的項目地址。一個動W態演示圖如下所示(這里 https://github.com/buaase/Calculator.git 就是我們 Fork 后倉庫的地址): -
在完成上述操作后,可在當前目錄下看到一個與倉庫同名的文件夾
Calculator
,這就是克隆到本地的項目。注意,默認克隆的分支是 java,請使用 git checkout cplusplus 命令切換到C++
項目。 進入項目文件夾,新建一個文件夾,重命名為你的Github
賬號名。 -
以 Github 賬號命名的文件夾作為項目目錄,打開 VS2017,點擊左上角的
文件
->新建
->項目
,如下圖所示,選擇Visual C++
中的控制台應用程序
。注意更改位置
參數到剛剛新建的文件夾所在的路徑。比如我的賬戶名為buaase
,剛剛新建的文件夾路徑為D:\Calculator\buaase
,解決方案的名稱也可以是Calculator
,自定義即可。
-
新建項目后會出現一些默認的
stdafx.cpp
與.h
為后綴的頭文件。找到與解決方案同名的cpp
文件,比如解決方案為ConsoleApplication1
,那么會有一個名叫ConsoleApplication1.cpp
的文件。將src
目錄下Calculator.cpp
文件的內容拷貝到該文件中。右鍵點擊頭文件
,新建一個頭文件,修改名稱為Calculator.h
,並將src
目錄下Calculator.h
文件的內容拷貝到新的頭文件中。此時,右鍵點擊解決方案,選擇編譯解決方案
,成功后點擊本地Windows調試器
即可運行,示意圖如下: -
接下來接連使用
git add,git commit -m "Message"
(Message是你要寫的內容)即可利用 Git 記錄下所有的改動。如果是初次使用 Git,請在使用上述兩條命令前使用如下兩條命令配置自己的個人郵箱與 Commit 時的用戶名,這里的郵箱和用戶名最好與 Github 賬號保持一致。$ git config --global user.name "John Doe" $ git config --global user.email johndoe@example.com
下面是一些常見的Git操作,可留作備忘
$ git clone [url] 下載一個項目以及它所有的版本歷史 $ git add [file] 將文件進行快照處理用於版本控制 $ git commit -m"[descriptive message]" 將文件快照永久地記錄在版本歷史中 $ git push 上傳當前本地分支commit到GitHub上 $ git pull 下載服務器上最新的本部並合並更改到本地 $ git reset [commit hash] 撤銷所有[commit hash]后的的commit,在本地保存更改 $ git log 列出當前分支的版本歷史
對於Github平台有疑問的,可以在 http://github.com/help 找到解決方案。
Part 3. 單元測試
要想在 VS2017 里對 C++ 項目進行單元測試,首先要新建一個測試項目。右鍵單擊解決方案,可以添加一個新建項目,在類型里選擇 單元測試
,我們這里新建了一個名為 CalculatorUnitTest
的單元測試項目。
在項目創建成功后,為單元測試項目 CalculatorUnitTest
增加對原項目的引用,以實現調用原項目函數接口的功能。
光設置引用還不夠,接下來讓我們手動設置一下測試項目的附加依賴項。選中單元測試項目,右鍵點擊選擇 屬性
在打開的左側菜單欄中選擇 配置屬性
-> 鏈接器
-> 輸入
,在 附加依賴項
的下拉選擇框中選擇 <編輯...>
,將被測試項目產生的所有 obj 文件路徑(注意:並非每次單元測試都固定寫 Calculator.obj ,它決定於 C++源文件的名字)寫到附加依賴項中,如下圖所示:
這兩個obj 文件可以在如下圖文件夾(Project/Debug/)中找到:
在完成單元測試的項目配置后,下面我們就可以開始寫單元測試代碼了。首先看向新創建的單元測試項目,里面應該會有一個默認的 unittest1.cpp
文件,打開該文件,應該是長這樣的:
#include "stdafx.h"
#include "CppUnitTest.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace CalculatorUnitTest
{
TEST_CLASS(UnitTest1)
{
public:
TEST_METHOD(TestMethod1)
{
//請輸入測試代碼
}
};
}
為了能順利引用剛剛寫好的接口,我們需要引入Calculator工程的接口定義頭文件,即 calculator.h。在頭文件部分插入一行
#include "../Calculator/calculator.h"
然后我們就可以順利引用相關接口了。通過閱讀方法 Solve 的注釋與代碼,我們不難發現,它的參數是字符串形式的四則運算表達式,返回的應該是該表達式的答案。現在我們來填充第一個測試用例,TEST_METHOD 其實就是一個宏,后面跟着的 TestMethod1 才是單元測試真正的名字。在該方法中插入如下代碼塊:
Calculator* calc = new Calculator();
string ret = calc->Solve("11+22");
Assert::AreEqual(ret, (string)"11+22=33");
這里我們用到了 Assert(斷言)。編寫單元測試時,我們總是會做出一些假設,比如我們期望一個函數在接受預期的輸入后就返回預期的輸出,斷言就是用於在代碼中捕捉這些假設。一般來說,單元測試中都會有斷言的存在,沒有斷言存在的單元測試其實是“假大空”的,沒有任何對程序輸入輸出的假設約束。
下面我們來運行一下這個單元測試,看 Solve 函數是否符合我們的期望。找到菜單欄中的 測試
,運行所有測試即可,如下圖所示
在單元測試運行完畢后,VS 的左側會彈出一個測試結果窗口。綠色代表通過,紅色代表失敗。從本次的結果來看,我們通過了這個單元測試。
那么也就是說,當 solve 函數的輸入為 "11+22"
時,其實際的輸出就是 "11+22=33"
,與預期現象溫和。當然,我們這里只是通過了一個簡單的測試用例,不能說這個函數就是一定正確的。所以我們需要加一些單元測試,以驗證在怎樣的情況下這個函數可能會出錯,現在請你幫助阿超補充一些針對 solve 方法的單元測試用例吧。
Part 4. 基本操作
上面我們學習了如何使用 IDE 進行單元測試,也測試出了 solve 方法的確有些問題。那么該如何定位問題所在呢?這就要用到 IDE 的調試功能了。下面我們就來介紹一下 Visual Studio 的調試方法。
-
斷點
調試程序首先要會設置斷點和單步運行。在 VS 中設置斷點非常簡單,在要設置斷點的行號旁用鼠標單擊一下就行了(注意要點到與右側編輯器顏色明顯不同的區域),如下圖所示,我們在第 31 行設了個斷點:
-
單步運行
在設置好斷點后,我們就可以啟動 Debug 模式。我們這里由於默認啟動項目是 Calculator ,所以直接點擊如下所示的
本地 Windows 調試器
按鈕即可開始調試。如果一個解決方案中有多個Cpp項目,要首先指定啟動項目。
啟動調試后,這時可以看到程序已經運行到剛剛打的斷點處前。下方的自動窗口可以看到各個變量的值。
與其他 IDE 類似,我們也可以通過手動設置監視一些感興趣的變量。點擊選項卡到
監視 1
中,按照下圖所示方式添加監視,可在界面中只顯示監控變量的值。此時我們的第31行代碼並沒有執行,下面我們利用單步運行的方法執行該語句。單步運行有兩種:Step Into(逐語句,快捷捷F11) 和 Step Over(逐過程,快捷捷F10),分別對應這兩個圖標。(這些圖標都在剛才啟動本地調試器按鈕的旁邊)
這兩種單步運行功能在運行語句時沒有區別,在執行方法調用語句時,Step Into 會跳入方法實現,Step Over 會直接執行完方法,實際使用中我們優先使用 Step Over,只有方法執行出錯了,說明程序問題在被調用方法中,這時再回來通過 Step Into 進入方法進行調試。我們單擊一下 Step Over 圖標(或 F10 ),程序停在了第 33 行(向右的小黃箭頭指示目前執行到第幾行,也可以使用這個圖標代表的按鈕 )
這時我們可以看到執行了 31 行代碼后 formulaChar 目前的值。
-
條件斷點
有些情況下我們只希望斷點在某些條件下才成立,該如何做呢?其實非常簡單,右鍵單擊紅色的斷點符號,即可彈出條件選項。
在這里我們可以輸入 Condition,設定為只有某些前置變量的值滿足條件時我們才會觸發斷點,幫助我們高效率測試。比如我們這里設定 Condition 為
j == 0
:從下圖中我們可以看到當斷點生效時,j 的值為 0。
我們現在的程序中暗藏了兩個BUG,一個是不符合題目的需求,另一個是實現上有一個小問題。現在請你利用剛學習到的單元測試與 Debug 的相關知識,找出程序的 Bug 吧!
Part 5. 回歸測試
單元測試不僅僅用來保證當前代碼的正確性,更重要的是用來保證代碼修復、改進或重構之后的正確性。也就是說,在每次修改完 Bug 之后,我們其實都需要運行一遍來看看是不是滿足之前所有的單元測試樣例。所以,在每次因為現有的 failed test 而修復原有代碼后,最好都全部運行一遍單元測試,保證以前 passed test 仍然是可以通過的。
同樣地,Git 的使用也是講究勤提交,提交的粒度最好是細到每個小功能的完成。一個小功能可以是一處小 Bug 的修復,也可以是一個簡單函數的實現。所以,在我們本次的編程訓練任務中,Git 至少會提交 2 次或以上。
Part 6. 效能工具介紹
為了測試並改進程序生成四則運算算式的效率,我們需要使用效能分析工具。效能分析工具並不能幫助我們直接改進算法的效率,但它可以幫我們分析找到代碼中執行效率最差,也就是所謂 效能瓶頸
的部分。這之后我們就可以把精力花費在改進瓶頸上,從而高效快速地提升程序性能。
Visual Studio 內置了非常棒的效能工具,學名叫做 性能探查器
。點擊 IDE 頂部菜單欄中的 分析
,即可看到 性能探查器
。
我們這里關注在程序的執行效率方面,所以我們選擇測試 CPU 使用率
即可。如果想探查內存泄露問題,也可以選擇使用其他選項。
先別急着開始探查。我們的代碼目前只產生 1 個四則運算算式,不存在性能問題。我們首先來給代碼多加幾百萬個循環,讓它運行 足夠長
時間,才能准確測出代碼的效能問題。增加循環體后的 main 函數體如下所示
int main()
{
for (int i = 0; i < 10000000; i++) {
Calculator* calc = new Calculator();
string question = calc->MakeFormula();
cout << question << endl;
string ret = calc->Solve("11+22");
cout << ret << endl;
}
}
好了,現在讓我們開始效能分析。即使程序沒有執行完成,效能分析也是可以強行結束的。讓程序跑幾十秒之后,就可以結束。點擊效能分析工具界面左上角的 停止收集
即可停止收集數據。
下圖就是一份完整的效能分析報告。
從圖中我們可以看到,Solve 方法在總 CPU 耗時中占了約 30% 左右,但如果想獲得更詳細的信息(比如具體到哪一行占了這么久,詳細報告閱讀起來更易懂),我們需要點擊上圖中的 創建詳細的報告...
,創建完成后會自動打開一個后綴為 .vspx
的文件,如下圖所示:
我們點進 Calculator::Solve 看看,可以看到非常清晰的每行代碼占用 CPU 的時間比例,如下圖左側所示。然后我們就可以着手改進代碼的效率,比如結合場景用更高效的數據結構,優化一些沒有用的代碼等等。
Part 7. 提交代碼
在完成 Debug
與 單元測試
之后,我們現在來學習一下如何提交代碼到 Github 上,並利用 Github 進行團隊協作。之前我們已經介紹過了 git add
與 git commit
命令,但這兩條命令只會對本地的倉庫進行修改,也就是說之前的所有操作都是離線的。我們要想讓 Github 上也跟蹤到最新的改變,就需要使用 git push
命令。
在使用該命令前,請確保所有本地的改動都已經 add
並 commit
了。可以用 git status
來檢查:
出現如圖所示的 nothing to commit
即說明已經可以 push 了。使用 push 命令后,會彈出一個窗口要求登錄 Github,此時輸入 Github 的 用戶名或郵箱
與 密碼
即可成功 push。
成功的提示如下所示,其中 master 部分應該是 java / cplusplus。
在完成 push 后,我們就可以開始向源倉庫(即阿超的倉庫)發起 Pull Request(簡稱 PR ,指發起請求給倉庫貢獻代碼)。打開你 Fork 后的項目主頁,如圖所示,點擊按鈕 New pull request
如果你按照教程的節奏一步步走下來了,那么在點擊 New Pull Request后,應該出現如下所示界面。如果不是,請聯系群內的助教/老師,或者在本博客下留言補充錯誤截圖。
此時點擊 Create pull request
即可發起請求。等待倉庫主人阿超通過審核后,你的代碼就可以成功合並進阿超的倉庫。至此就完成了整個教程,恭喜!
參考鏈接:
- VS 下載與安裝:https://zhuanlan.zhihu.com/p/33981517
- VS2017 C++單元測試:https://www.cnblogs.com/HBING/p/7492597.html
- Git 交互式教程:https://learngitbranching.js.org/