在循环中,程序会提取字符的随机位置以便从可能位置列表进行变化,然后调用帮助程序方法来生成变化的 Class1.cs 源代码,构建相应的变化 MathLib.dll,重新构建测试工具以便使用新的变化,然后测试变化的 DLL,并希望会生成错误。 因为变化的源代码很可能是无效的,所以我将构建和测试尝试封装在 try-catch 语句中,以便可以中止对不可构建的代码的测试。
Main 方法封装为:
... Console.WriteLine("\nMutation test run complete"); } catch (Exception ex) { Console.WriteLine("Fatal: "+ ex.Message); } } // Main() |
创建变化源代码
获取可能的变化位置列表的帮助程序方法是:
static List<int> GetMutationPositions(string originalSourceFile) { StreamReader sr = File.OpenText(originalSourceFile); int ch =0; int pos =0; List<int> list =new List<int>(); while ((ch = sr.Read()) !=-1) { if ((char)ch =='>'|| (char)ch =='<') list.Add(pos); ++pos; } sr.Close(); return list; } |
该方法逐个字符匹配源代码,寻找大于和小于运算符,并将字符位置添加到 List 集合中。 请注意,这里介绍的超简单变化测试系统存在一项限制,即只能变化单字符的符号,如“>”或“+”,而不能变化多字符的符号,如“>=”。 实际用于变化 SUT 源代码的帮助程序方法如图 4 所示。
图 4 CreateMutantSource 方法
staticvoid CreateMutantSource(string originalSourceFile, int mutatePosition, string mutatedSourceFile) { FileStream ifs =new FileStream(originalSourceFile, FileMode.Open); StreamReader sr =new StreamReader(ifs); FileStream ofs =new FileStream(mutatedSourceFile, FileMode.Create); StreamWriter sw =new StreamWriter(ofs); int currPos =0; int currChar; while ((currChar = sr.Read()) !=-1) { if (currPos == mutatePosition) { if ((char)currChar =='<') { sw.Write('>'); } elseif ((char)currChar =='>') { sw.Write('<'); } else sw.Write((char)currChar); } else sw.Write((char)currChar); ++currPos; } sw.Close(); ofs.Close(); sr.Close(); ifs.Close(); } |
CreateMutantSource 方法接受原始的源代码文件(已提前保存),还接受要变化的字符位置和生成的变化文件的名称及保存位置。 此处,我仅检查“<”和“>”字符,但您可能希望看一下其他变化。 通常,您希望变化会产生有效的源,因此您不能将“>”改成“=”。 此外,在多个位置上变化也是不可取的,因为这多个变化中可能只有一个变化会生成新的测试用例失败,从而表明测试集有效,但其实并非如此。 一些变化没有实用性(例如变化注释里的字符),另一些变化会产生无效代码(例如将移位运算符“>>””更改为“><“)。