對(duì)單元測(cè)試的描述大家可自行百度,后期時(shí)間滿足的情況下儡毕,我在對(duì)單元測(cè)試進(jìn)行一個(gè)單獨(dú)的專題進(jìn)行說明簇捍,這一節(jié)主要就是介紹一下簡(jiǎn)單的用法。
首先我們創(chuàng)建一個(gè)控制臺(tái)項(xiàng)目杜漠,添加引用 system.windows.forms,為了下面的類做鋪墊
第一步 首先創(chuàng)建控制臺(tái)項(xiàng)目极景,添加類 WC.cs
本類主要是對(duì)文件文字總字?jǐn)?shù)的一個(gè)幫助類,接下去的單位測(cè)試也是基于它進(jìn)行驾茴,首先附上代碼
public class WC
{
private string sFilename; // 文件名
private string[] sParameter; // 參數(shù)數(shù)組
private int iCharcount; // 字符數(shù)
private int iWordcount; // 單詞數(shù)
private int iLinecount; // 行 數(shù)
private int iNullLinecount; // 空行數(shù)
private int iCodeLinecount; // 代碼行數(shù)
private int iNoteLinecount; // 注釋行數(shù)
// 初始化
public WC()
{
this.iCharcount = 0;
this.iWordcount = 0;
this.iLinecount = 0;
this.iNullLinecount = 0;
this.iCodeLinecount = 0;
this.iNoteLinecount = 0;
}
// 控制信息
public string Operator(string[] sParameter, string sFilename)
{
this.sParameter = sParameter;
this.sFilename = sFilename;
string retrun_str = "";
foreach (string s in sParameter)
{
if (s == "-x")
{
string resultFile = "";
OpenFileDialog fd = new OpenFileDialog();
fd.InitialDirectory = "D:\\Patch";
fd.Filter = "All files (*.*)|*.*|txt files (*.txt)|*.txt";
fd.FilterIndex = 2;
fd.RestoreDirectory = true;
if (fd.ShowDialog() == DialogResult.OK)
{
resultFile = fd.FileName;
//Console.WriteLine("文件名:{0}", resultFile);
SuperCount(resultFile);
BaseCount(resultFile);
retrun_str = DisplayAll();
}
break;
}
// 遍歷文件
else if (s == "-s")
{
try
{
string[] arrPaths = sFilename.Split('\\');
int pathsLength = arrPaths.Length;
string path = "";
// 獲取輸入路徑
for (int i = 0; i < pathsLength - 1; i++)
{
arrPaths[i] = arrPaths[i] + '\\';
path += arrPaths[i];
}
// 獲取通配符
string filename = arrPaths[pathsLength - 1];
// 獲取符合條件的文件名
string[] files = Directory.GetFiles(path, filename);
foreach (string file in files)
{
//Console.WriteLine("文件名:{0}", file);
SuperCount(file);
BaseCount(file);
retrun_str = Display();
}
break;
}
catch (IOException ex)
{
//Console.WriteLine(ex.Message);
return "";
}
}
// 高級(jí)選項(xiàng)
else if (s == "-a")
{
//Console.WriteLine("文件名:{0}", sFilename);
SuperCount(sFilename);
BaseCount(sFilename);
retrun_str = Display();
break;
}
// 基本功能
else if (s == "-c" || s == "-w" || s == "-l")
{
//Console.WriteLine("文件名:{0}", sFilename);
BaseCount(sFilename);
retrun_str = Display();
break;
}
else
{
//Console.WriteLine("參數(shù) {0} 不存在", s);
break;
}
}
Console.WriteLine("{0}", retrun_str);
return retrun_str;
}
// 統(tǒng)計(jì)基本信息:字符數(shù) 單詞數(shù) 行數(shù)
private void BaseCount(string filename)
{
try
{
// 打開文件
FileStream file = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
StreamReader sr = new StreamReader(file);
int nChar;
int charcount = 0;
int wordcount = 0;
int linecount = 0;
//定義一個(gè)字符數(shù)組
char[] symbol = { ' ', ',', '.', '?', '!', ':', ';', '\'', '\"', '\t', '{', '}', '(', ')', '+' ,'-',
'*', '='};
while ((nChar = sr.Read()) != -1)
{
charcount++; // 統(tǒng)計(jì)字符數(shù)
foreach (char c in symbol)
{
if (nChar == (int)c)
{
wordcount++; // 統(tǒng)計(jì)單詞數(shù)
}
}
if (nChar == '\n')
{
linecount++; // 統(tǒng)計(jì)行數(shù)
}
}
iCharcount = charcount;
iWordcount = wordcount + 1;
iLinecount = linecount + 1;
sr.Close();
}
catch (IOException ex)
{
Console.WriteLine(ex.Message);
return;
}
}
// 統(tǒng)計(jì)高級(jí)信息:空行數(shù) 代碼行數(shù) 注釋行數(shù)
private void SuperCount(string filename)
{
try
{
// 打開文件
FileStream file = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
StreamReader sr = new StreamReader(file);
String line;
int nulllinecount = 0;
int codelinecount = 0;
int notelinecount = 0;
while ((line = sr.ReadLine()) != null)
{
line = line.Trim(' ');
line = line.Trim('\t');
// 空行
if (line == "" || line.Length <= 1)
{
nulllinecount++;
}
// 注釋行
else if (line.Substring(0, 2) == "http://" || line.Substring(1, 2) == "http://")
{
notelinecount++;
}
// 代碼行
else
{
codelinecount++;
}
}
iNullLinecount = nulllinecount;
iCodeLinecount = codelinecount;
iNoteLinecount = notelinecount;
sr.Close();
}
catch (IOException ex)
{
Console.WriteLine(ex.Message);
return;
}
}
// 打印信息
private string Display()
{
string return_str = "";
foreach (string s in sParameter)
{
if (s == "-c")
{
//Console.WriteLine("字 符 數(shù):{0}", iCharcount);
return_str += "字符數(shù):" + iCharcount.ToString();
}
else if (s == "-w")
{
//Console.WriteLine("單 詞 數(shù):{0}", iWordcount);
return_str += "單詞數(shù):" + iWordcount.ToString();
}
else if (s == "-l")
{
//Console.WriteLine("總 行 數(shù):{0}", iLinecount);
return_str += "總行數(shù):" + iLinecount.ToString();
}
else if (s == "-a")
{
//Console.WriteLine("空 行 數(shù):{0}", iNullLinecount);
//Console.WriteLine("代碼行數(shù):{0}", iCodeLinecount);
//Console.WriteLine("注釋行數(shù):{0}", iNoteLinecount);
return_str += "空行數(shù):" + iNullLinecount.ToString();
return_str += "代碼行數(shù):" + iCodeLinecount.ToString();
return_str += "注釋行數(shù):" + iNoteLinecount.ToString();
}
}
//Console.WriteLine();
return return_str;
}
private string DisplayAll()
{
string return_str = "";
foreach (string s in sParameter)
{
//Console.WriteLine("字 符 數(shù):{0}", iCharcount);
//Console.WriteLine("單 詞 數(shù):{0}", iWordcount);
//Console.WriteLine("總 行 數(shù):{0}", iLinecount);
//Console.WriteLine("空 行 數(shù):{0}", iNullLinecount);
//Console.WriteLine("代碼行數(shù):{0}", iCodeLinecount);
//Console.WriteLine("注釋行數(shù):{0}", iNoteLinecount);
return_str += "字符數(shù):" + iCharcount.ToString();
return_str += "單詞數(shù):" + iWordcount.ToString();
return_str += "總行數(shù):" + iLinecount.ToString();
return_str += "空行數(shù):" + iNullLinecount.ToString();
return_str += "代碼行數(shù):" + iCodeLinecount.ToString();
return_str += "注釋行數(shù):" + iNoteLinecount.ToString();
}
//Console.WriteLine();
return return_str;
}
}
第二步 添加單元測(cè)試
LZ使用的是VS2017,通過右擊可以得到如下截圖所示內(nèi)容盼樟,點(diǎn)擊創(chuàng)建單元測(cè)試,保持默認(rèn)選項(xiàng)不變锈至,點(diǎn)擊確認(rèn)
單擊 “創(chuàng)建單元測(cè)試” 后晨缴,會(huì)出項(xiàng)如下對(duì)話框。不用修改峡捡,保持默認(rèn)選項(xiàng)就可以击碗。
如果菜單沒有顯示 測(cè)試筑悴,可以參照這篇博客進(jìn)行設(shè)置。http://www.bubuko.com/infodetail-1370830.html
添加后的結(jié)果如下
進(jìn)行單元測(cè)試
接下來稍途,我們對(duì)測(cè)試代碼進(jìn)行修改阁吝,在我們進(jìn)行單元測(cè)試時(shí),某種程度上就是將我們?nèi)斯そo出的程序運(yùn)行結(jié)果與程序?qū)嶋H輸出結(jié)果進(jìn)行比較械拍,所以單元測(cè)試的過程一般分為 3 步:
給出我們期望的結(jié)果 expected
執(zhí)行需測(cè)試代碼突勇,返回結(jié)果 actual
比較 actual 和 expected
下面以 WC 程序執(zhí)行 -c 參數(shù)對(duì) 123.txt 文件進(jìn)行統(tǒng)計(jì)的功能為例進(jìn)行測(cè)試,我們將測(cè)試代碼修改如下殊者,其中 AreEqual 方法用于對(duì)期望值與實(shí)際值進(jìn)行比較与境。
using Microsoft.VisualStudio.TestTools.UnitTesting;
using ConsoleApp2;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp2.Tests
{
[TestClass()]
public class WCTests
{
[TestMethod()]
public void WCTest()
{
// arrange
string expected = "字符數(shù):138";
WC testwc = new WC();
// act
string[] opar = new string[1];
opar[0] = "-c";
string actual = testwc.Operator(opar, @"D:\學(xué)習(xí)\我的工程\軟件工程\wc\wc\wc\123.txt");
// assert
Assert.AreEqual(expected, actual);
}
}
}
開始調(diào)試&輸出結(jié)果
"123.txt" 文件內(nèi)容:
namespace ConsoleApp2
{
class Program
{
static void Main(string[] args)
{
}
}
}
我們預(yù)期的測(cè)試結(jié)果是此文件有124個(gè)字符,所以會(huì)輸出 “字符數(shù):124” 猖吴;我們來看看測(cè)試的結(jié)果摔刁,點(diǎn)擊右鍵,選擇 “運(yùn)行測(cè)試” 海蔽,選項(xiàng)測(cè)試通過了共屈。
如果我們預(yù)期此文件有130個(gè)字符,單元測(cè)試就會(huì)報(bào)錯(cuò)党窜,并且給出比對(duì)結(jié)果
編寫測(cè)試方法
單元測(cè)試的基本方法是調(diào)用被測(cè)代碼的函數(shù)拗引,輸入函數(shù)的參數(shù)值,獲取返回結(jié)果幌衣,然后與預(yù)期測(cè)試結(jié)果進(jìn)行比較矾削,如果相等則認(rèn)為測(cè)試通過,否則認(rèn)為測(cè)試不通過豁护。
1哼凯、Assert類的使用
Assert.Inconclusive() 表示一個(gè)未驗(yàn)證的測(cè)試;
Assert.AreEqual() 測(cè)試指定的值是否相等楚里,如果相等断部,則測(cè)試通過;
AreSame() 用于驗(yàn)證指定的兩個(gè)對(duì)象變量是指向相同的對(duì)象班缎,否則認(rèn)為是錯(cuò)誤
AreNotSame() 用于驗(yàn)證指定的兩個(gè)對(duì)象變量是指向不同的對(duì)象蝴光,否則認(rèn)為是錯(cuò)誤
Assert.IsTrue() 測(cè)試指定的條件是否為True,如果為True达址,則測(cè)試通過蔑祟;
Assert.IsFalse() 測(cè)試指定的條件是否為False,如果為False沉唠,則測(cè)試通過做瞪;
Assert.IsNull() 測(cè)試指定的對(duì)象是否為空引用,如果為空,則測(cè)試通過装蓬;
Assert.IsNotNull() 測(cè)試指定的對(duì)象是否為非空,如果不為空纱扭,則測(cè)試通過牍帚;
2、CollectionAssert類的使用
用于驗(yàn)證對(duì)象集合是否滿足條件
StringAssert類的使用
用于比較字符串乳蛾。
StringAssert.Contains
StringAssert.Matches
StringAssert.tartWith