白盒测试(white-box testing)又称透明盒测试(glass box testing)、结构测试(structural testing)等,软件测试的主要方法之一,也称结构测试、逻辑驱动测试或基于程序本身的测试。测试应用程序的内部结构或运作,而不是测试应用程序的功能(即黑盒测试)。在白盒测试时,以编程语言的角度来设计测试案例。测试者输入数据验证数据流在程序中的流动路径,并确定适当的输出,类似测试电路中的节点。测试者了解待测试程序的内部结构、算法等信息,这是从程序设计者的角度对程序进行的测试。
白盒测试可以应用于单元测试(unit testing)、集成测试(integration testing)和系统的软件测试流程,可测试在集成过程中每一单元之间的路径,或者主系统跟子系统中的测试。尽管这种测试的方法可以发现许多的错误或问题,它可能无法检测未使用部分的规范。
如果我们能获得win8应用代码的话,那么就可以使用Visual Studio进行有关白盒测试,这里我们不妨选择其自带的模板单元测试进行设计,下面是实验的步骤:
(一)创建解决方案和单元测试项目:
(1) 在“文件”菜单上选择“新建”,然后选择“新建项目”。
(2) 在“新建项目”对话框中,展开“已安装”、“Visual C#”,选择“Windows Store”。 然后从项目模板列表中选择“空白应用程序”。
(3) 将项目命名为 isLeapYear,并确保选中“创建解决方案的目录”。
(4) 在解决方案资源管理器中,选择解决方案名称,从快捷菜单中选择“添加”,然后选择“新建项目”。
(5) 在“新建项目”对话框中,展开“已安装”、“Visual C#”,然后选择“Windows 应用商店”。 然后从项目模板列表中选择“单元测试库(Windows Store 应用程序)”。
(6) 在 Visual Studio 编辑器中打开 UnitTest1.cs。
请注意:
- 每个测试都是使用 [TestMethod] 定义的。 测试方法必须返回 void,并且不能具有任何参数。
- 测试方法必须位于使用 [TestClass] 特性修饰的类中。
运行测试时,将为每个测试类创建一个实例。 将按未指定顺序调用测试方法。
向isLeapYear项目添加Judge类:
(1) 在“解决方案资源管理器”中,选择“isLeapYear”项目名称。 从快捷 菜单中选择“添加”,然后选择“类”。
(2) 将类文件命名为 Judge.cs
(3) 将以下代码添加到 Judge 类 Judge.cs 文件中:
将测试项目合并为应用程序项目:
(1) 将对 isLeapYear 应用程序的引用添加到 UnitTestLibrary1项目。
- 在解决方案资源管理器中,选择“UnitTestLibrary1”项目,然后选择快捷菜单上的“添加引用...”。
- 在“添加引用 - UnitTestLibrary1”对话框上,展开“解决方案”,再选择“项目”。 然后选择“isLeapYear”项目。
(2) 向 UnitTest1.cs 文件添加 using 语句:
- 打开 UnitTest1.cs。
- 在using语句中添加using isLeapYear;
(3) 添加使用 Judge 函数的测试。 将下列代码添加到 UnitTest1.cs:
(4) 生成解决方案。新测试将显示在测试资源管理器的“未运行的测试”节点中。
(5) 在测试资源管理器中,选择“全部运行”。
(二)根据代码画出程序流程图和程序流图:
图1-程序流程图
图2-程序流图
(三)实验分析
- 测试用例和结果
测试环境:Win8系统+Visual Studio 2013 Ultimate
(flag = 1 表示该年是闰年;flag = 0表示该年不是闰年;flag = -1表示非法输入; flag=2表示在公元1582年后才有“闰年”一说)
表1--测试用例
测试编号 |
输入 |
预期输出 |
实际输出 |
覆盖路径 |
是否通过测试 |
1 |
1400 |
flag=2 |
flag=2 |
1→2→3→4→5 |
是 |
2 |
flag=-1 |
flag=-1 |
1→2→11→12 |
是 |
|
3 |
2000 |
flag=1 |
flag=1 |
1→2→3→6→7→8 |
是 |
4 |
1864 |
flag=1 |
flag=1 |
1→2→3→6→9→10→7→8 |
是 |
5 |
2002 |
flag=0 |
flag=0 |
1→2→3→6→9→10→13→14 |
是 |
6 |
1700 |
flag=0 |
flag=0 |
1→2→3→6→9→13→14 |
是 |
7 |
1769 |
flag=0 |
flag=0 |
1→2→3→6→9→10→13→14 |
是 |
8 |
-298 |
flag=2 |
flag=2 |
1→2→3→4→5 |
是 |
9 |
Abc12 |
flag=1 |
flag=1 |
1→2→11→12 |
是 |
10 |
中国 |
flag=1 |
flag=1 |
1→2→11→12 |
是 |
针对各类测试用例的过程截图(每类路径举例一个)
(1)
(2)
(3)
(4)
(5)
(6)
(四)实验结果
经过验证,通过手动添加断言,来判断测试是否通过,即Assert.AreEqual(expected, test); 如果expected和test不等,则表示测试通过反之不通过,在该应用中通过验证所有测试用例均通过,因而暂没发现bug。
结果截图:(分别为测试通过和未通过的截图,其他类似,不再一一罗列)
(五)实验结论及源代码
在本实验中使用的是路径覆盖,通过程序流程图和程序流图得出测试用例,因而具有全面性和代表性。当然白盒测试并非完美,亦有不足之处,比如无法检测代码中遗漏的路径和数据敏感性错误、代价昂贵等。
(1)App.xaml.cs:
1 using System; 2 using System.Collections.Generic; 3 using System.IO; 4 using System.Linq; 5 using System.Runtime.InteropServices.WindowsRuntime; 6 using Windows.ApplicationModel; 7 using Windows.ApplicationModel.Activation; 8 using Windows.Foundation; 9 using Windows.Foundation.Collections; 10 using Windows.UI.Xaml; 11 using Windows.UI.Xaml.Controls; 12 using Windows.UI.Xaml.Controls.Primitives; 13 using Windows.UI.Xaml.Data; 14 using Windows.UI.Xaml.Input; 15 using Windows.UI.Xaml.Media; 16 using Windows.UI.Xaml.Navigation; 17 18 // “空白应用程序”模板在 http://go.microsoft.com/fwlink/?LinkId=234227 上有介绍 19 20 namespace isLeapYear 21 { 22 /// <summary> 23 /// 提供特定于应用程序的行为,以补充默认的应用程序类。 24 /// </summary> 25 sealed partial class App : Application 26 { 27 /// <summary> 28 /// 初始化单一实例应用程序对象。 这是执行的创作代码的第一行, 29 /// 逻辑上等同于 main() 或 WinMain()。 30 /// </summary> 31 public App() 32 { 33 this.InitializeComponent(); 34 this.Suspending += OnSuspending; 35 } 36 37 /// <summary> 38 /// 在应用程序由最终用户正常启动时进行调用。 39 /// 以打开特定文件等情况下使用其他入口点。 40 /// </summary> 41 /// <param name="e">有关启动请求和过程的详细信息。</param> 42 protected override void OnLaunched(LaunchActivatedEventArgs e) 43 { 44 45 #if DEBUG 46 if (System.Diagnostics.Debugger.IsAttached) 47 { 48 this.DebugSettings.EnableFrameRateCounter = true; 49 } 50 #endif 51 52 Frame rootFrame = Window.Current.Content as Frame; 53 54 // 不要在窗口已包含内容时重复应用程序初始化, 55 // 只需确保窗口处于活动状态 56 if (rootFrame == null) 57 { 58 // 创建要充当导航上下文的框架,并导航到第一页 59 rootFrame = new Frame(); 60 //设置默认语言 61 rootFrame.Language = Windows.Globalization.ApplicationLanguages.Languages[0]; 62 63 rootFrame.NavigationFailed += OnNavigationFailed; 64 65 if (e.PreviousExecutionState == ApplicationExecutionState.Terminated) 66 { 67 //TODO: 从之前挂起的应用程序加载状态 68 } 69 70 // 将框架放在当前窗口中 71 Window.Current.Content = rootFrame; 72 } 73 74 if (rootFrame.Content == null) 75 { 76 // 当未还原导航堆栈时,导航到第一页, 77 // 并通过将所需信息作为导航参数传入来配置 78 // 参数 79 rootFrame.Navigate(typeof(MainPage), e.Arguments); 80 } 81 // 确保当前窗口处于活动状态 82 Window.Current.Activate(); 83 } 84 85 /// <summary> 86 ///导航到特定页失败时调用 87 /// </summary> 88 ///<param name="sender">导航失败的框架</param> 89 ///<param name="e">有关导航失败的详细信息</param> 90 void OnNavigationFailed(object sender, NavigationFailedEventArgs e) 91 { 92 throw new Exception("Failed to load Page " + e.SourcePageType.FullName); 93 } 94 95 /// <summary> 96 /// 在将要挂起应用程序执行时调用。 在不知道应用程序 97 /// 将被终止还是恢复的情况下保存应用程序状态, 98 /// 并让内存内容保持不变。 99 /// </summary> 100 /// <param name="sender">挂起的请求的源。</param> 101 /// <param name="e">有关挂起的请求的详细信息。</param> 102 private void OnSuspending(object sender, SuspendingEventArgs e) 103 { 104 var deferral = e.SuspendingOperation.GetDeferral(); 105 //TODO: 保存应用程序状态并停止任何后台活动 106 deferral.Complete(); 107 } 108 } 109 }
(2)MainPage.xaml.cs:
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls.Primitives; using Windows.UI.Xaml.Data; using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; // “空白页”项模板在 http://go.microsoft.com/fwlink/?LinkId=234238 上有介绍 namespace isLeapYear { /// <summary> /// 可用于自身或导航至 Frame 内部的空白页。 /// </summary> public sealed partial class MainPage : Page { public MainPage() { this.InitializeComponent(); } private void button_Click(object sender, RoutedEventArgs e) { Frame.Navigate(typeof(Result), textBox.Text); } } }
(3)Result.xaml.cs:
1 using System; 2 using System.Collections.Generic; 3 using System.IO; 4 using System.Linq; 5 using System.Runtime.InteropServices.WindowsRuntime; 6 using Windows.Foundation; 7 using Windows.Foundation.Collections; 8 using Windows.UI.Xaml; 9 using Windows.UI.Xaml.Controls; 10 using Windows.UI.Xaml.Controls.Primitives; 11 using Windows.UI.Xaml.Data; 12 using Windows.UI.Xaml.Input; 13 using Windows.UI.Xaml.Media; 14 using Windows.UI.Xaml.Navigation; 15 16 17 // “空白页”项模板在 http://go.microsoft.com/fwlink/?LinkId=234238 上有介绍 18 19 namespace isLeapYear 20 { 21 /// <summary> 22 /// 可用于自身或导航至 Frame 内部的空白页。 23 /// </summary> 24 public sealed partial class Result : Page 25 { 26 public Result() 27 { 28 this.InitializeComponent(); 29 } 30 protected override void OnNavigatedTo(NavigationEventArgs e) 31 { 32 string year = e.Parameter as String; 33 //判断传递数据是否为空 34 Judge judge = new Judge(); 35 if (judge.isLeapYear(year) == 1) 36 textBlock.Text = year + "年是闰年"; 37 else if (judge.isLeapYear(year) == 0) 38 textBlock.Text = year + "年不是闰年"; 39 else if (judge.isLeapYear(year) == 2) 40 textBlock.Text = "公元1582年后方有\"闰年\"一说"; 41 else 42 textBlock.Text = "请输入合法年份"; 43 44 } 45 46 private void button1_Click(object sender, RoutedEventArgs e) 47 { 48 Frame.Navigate(typeof(MainPage)); 49 } 50 } 51 }
(4)Judge.cs:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace isLeapYear 8 { 9 public class Judge 10 { 11 public Judge() 12 { 13 14 } 15 public int isLeapYear(String year) 16 { 17 int flag; 18 try 19 { 20 int test = int.Parse(year); 21 if (test <= 1582) 22 flag = 2; 23 else if (test % 400 == 0) 24 flag = 1; 25 else if (test % 100 == 0) 26 flag = 0; 27 else if (test % 4 == 0) 28 flag = 1; 29 else 30 flag = 0; 31 } 32 catch (Exception ex) 33 { 34 flag = -1; 35 } 36 return flag; 37 } 38 } 39 } 40 (5) UnitTest.cs: 41 using System; 42 using System.Collections.Generic; 43 using System.Linq; 44 using System.Text; 45 using Microsoft.VisualStudio.TestPlatform.UnitTestFramework; 46 using isLeapYear; 47 48 namespace UnitTestLibrary1 49 { 50 [TestClass] 51 public class UnitTest1 52 { 53 [TestMethod] 54 public void TestMethod1() 55 { 56 Judge judge = new Judge(); 57 String year = "2012"; 58 int test = judge.isLeapYear(year); 59 int expected = 1; 60 Assert.AreEqual(expected, test); 61 } 62 63 } 64 }