单元测试框架"艾信.NET单元测试工具(AssionUnit)"开发---第二步
*接上一次的第一部,当时实现了框架的大至思想和特性\程序集的动态载入等.这一节实现了基本的测试功能,现在放出来大家讨论.
上一节中我有提到过,BUG的跟踪可以用异常来实现,用纯c#做我也实在想不出还有其它的方法了,也就是自定义异常/系统异常抛出,
客户端来接收这个异常信息,有套机制来验证和跟踪记录BUG是否存在和存在数量/存在位置等等..
下面是工具中捕捉异常记录bug的代码,通过反射程序集,动态调用测试用例方法.接收抛出的异常,如果有异常则记录bug点:
测试用例示例:
开发过程中遇到了一个问题,WinForm自带的进度条控件不支持列改色彩,就是说是随着系统主题的(windowsxp以上系统),后来实在没有办法只
好自己实现一个简单的进度条自定义控件,虽然丑了一点,但终于可以变红色了哈哈.附带下控件的代码:
老规距最后来一张运行效果图:
我写的不是代码,是轮子!
上一节中我有提到过,BUG的跟踪可以用异常来实现,用纯c#做我也实在想不出还有其它的方法了,也就是自定义异常/系统异常抛出,
客户端来接收这个异常信息,有套机制来验证和跟踪记录BUG是否存在和存在数量/存在位置等等..
下面是工具中捕捉异常记录bug的代码,通过反射程序集,动态调用测试用例方法.接收抛出的异常,如果有异常则记录bug点:
Code
/// <summary>
/// 测试方法
/// </summary>
protected void TestingStart()
{
txtMainMessage.Text = string.Empty; //初初提示信息
if (asserblyName.Length <= 0)
{
MessageBox.Show("请载入要测试的程序集");
return;
}
bool isBug = false; //Bug状态记数器,默认为无BUG
int isBugCount = 0; //Bug数据记数,默认为0
AlertsType isBugAlert = AlertsType.Red;//默认提示色为红色
Assembly assembly = Assembly.LoadFrom(asserblyName); //载入程序集
Type[] types = assembly.GetTypes(); //反射出所有类型
assionProgressBar1.Maximum = types.Length;//进度条最大值为类型数
assionProgressBar1.Value = 0;//当前进度为起始 0
assionProgressBar1.ProgressBarColor = Color.Green;//默认为绿色
//循环类型
foreach (var t in types)
{
TestClassAttribute testClass = IsCustomerAttribute.GetTestClassAttribute(t); //查询特性
//如果没有标记测试类,返回下一次循环
if (testClass == null)
continue;
//循环方法
foreach (var m in t.GetMethods())
{
TestAttribute test = IsCustomerAttribute.GetTestAttribute(m); //查询特性
//如果没有标记测试方法,返回下一次循环
if (test == null)
continue;
//如果有黄色提示特性则显示为黄色
if (test.IsAlertType == AlertsType.Yellow)
isBugAlert = AlertsType.Yellow;
BindingFlags flags = BindingFlags.DeclaredOnly | BindingFlags.Public;
object instance = null;
//如果不是静态方法,则实例方法
if (!m.IsStatic)
{
instance = Instantiate(t);
flags |= BindingFlags.Instance;
}
else
{
flags |= BindingFlags.Static;
}
//执行测试方法,并捕取异常信息
try
{
m.Invoke(instance, flags, null, null, null);
}
catch (Exception exp)
{
Exception bugException = exp.InnerException; //获取具体内部异常
//转换为Bug异常
try
{
BugException bexp = (BugException)bugException;
//如果是显示抛出BUG异常信息,则记录Bug
if (bexp.Message == "TestingBugReturn")
{
txtMainMessage.Text += "BUG:" + t.Name.ToString() + "-" + m.Name.ToString() + "\r\n\r\n"; //记录Bug位置
isBug = true; //有Bug
isBugCount++; //Bug+1次
}
}
catch
{
txtMainMessage.Text += exp.InnerException.Message + "\r\n\r\n";
isBug = true;
isBugCount++;
continue;
}
}
}
assionProgressBar1.Value++;//循环一次步长加一步
Application.DoEvents();
}
if (isBug == true)
{
if (isBugAlert == AlertsType.Red)
assionProgressBar1.ProgressBarColor = Color.Red; //有Bug显示红色
else
assionProgressBar1.ProgressBarColor = Color.Yellow; //有黄色提示特性显示黄色提示
lblBug.Text = "共有Bug" + isBugCount.ToString() + "个";
}
else
{
assionProgressBar1.ProgressBarColor = Color.Green; //无Bug显示黄色
lblBug.Text = "共有Bug" + isBugCount.ToString() + "个";
}
}
/// <summary>
/// 测试方法
/// </summary>
protected void TestingStart()
{
txtMainMessage.Text = string.Empty; //初初提示信息
if (asserblyName.Length <= 0)
{
MessageBox.Show("请载入要测试的程序集");
return;
}
bool isBug = false; //Bug状态记数器,默认为无BUG
int isBugCount = 0; //Bug数据记数,默认为0
AlertsType isBugAlert = AlertsType.Red;//默认提示色为红色
Assembly assembly = Assembly.LoadFrom(asserblyName); //载入程序集
Type[] types = assembly.GetTypes(); //反射出所有类型
assionProgressBar1.Maximum = types.Length;//进度条最大值为类型数
assionProgressBar1.Value = 0;//当前进度为起始 0
assionProgressBar1.ProgressBarColor = Color.Green;//默认为绿色
//循环类型
foreach (var t in types)
{
TestClassAttribute testClass = IsCustomerAttribute.GetTestClassAttribute(t); //查询特性
//如果没有标记测试类,返回下一次循环
if (testClass == null)
continue;
//循环方法
foreach (var m in t.GetMethods())
{
TestAttribute test = IsCustomerAttribute.GetTestAttribute(m); //查询特性
//如果没有标记测试方法,返回下一次循环
if (test == null)
continue;
//如果有黄色提示特性则显示为黄色
if (test.IsAlertType == AlertsType.Yellow)
isBugAlert = AlertsType.Yellow;
BindingFlags flags = BindingFlags.DeclaredOnly | BindingFlags.Public;
object instance = null;
//如果不是静态方法,则实例方法
if (!m.IsStatic)
{
instance = Instantiate(t);
flags |= BindingFlags.Instance;
}
else
{
flags |= BindingFlags.Static;
}
//执行测试方法,并捕取异常信息
try
{
m.Invoke(instance, flags, null, null, null);
}
catch (Exception exp)
{
Exception bugException = exp.InnerException; //获取具体内部异常
//转换为Bug异常
try
{
BugException bexp = (BugException)bugException;
//如果是显示抛出BUG异常信息,则记录Bug
if (bexp.Message == "TestingBugReturn")
{
txtMainMessage.Text += "BUG:" + t.Name.ToString() + "-" + m.Name.ToString() + "\r\n\r\n"; //记录Bug位置
isBug = true; //有Bug
isBugCount++; //Bug+1次
}
}
catch
{
txtMainMessage.Text += exp.InnerException.Message + "\r\n\r\n";
isBug = true;
isBugCount++;
continue;
}
}
}
assionProgressBar1.Value++;//循环一次步长加一步
Application.DoEvents();
}
if (isBug == true)
{
if (isBugAlert == AlertsType.Red)
assionProgressBar1.ProgressBarColor = Color.Red; //有Bug显示红色
else
assionProgressBar1.ProgressBarColor = Color.Yellow; //有黄色提示特性显示黄色提示
lblBug.Text = "共有Bug" + isBugCount.ToString() + "个";
}
else
{
assionProgressBar1.ProgressBarColor = Color.Green; //无Bug显示黄色
lblBug.Text = "共有Bug" + isBugCount.ToString() + "个";
}
}
测试用例示例:
Code
/// <summary>
/// 用于测试 BasicModule类
/// </summary>
[TestClass]
public class BasicModuleTest
{
/// <summary>
/// 测试Add方法
/// </summary>
[Test]
public void Add()
{
BasicModule bm = new BasicModule();
int result = bm.Add(1, 2);
Assert.AreEqual(result, 4);
}
/// <summary>
/// 测试Add方法
/// </summary>
[Test]
public void Add2()
{
BasicModule bm = new BasicModule();
int result = bm.Add(1, 2);
if (result != 5)
Assert.BugBool(true);
else
Assert.BugBool(false);
}
}
/// <summary>
/// 用于测试 BasicModule类
/// </summary>
[TestClass]
public class BasicModuleTest
{
/// <summary>
/// 测试Add方法
/// </summary>
[Test]
public void Add()
{
BasicModule bm = new BasicModule();
int result = bm.Add(1, 2);
Assert.AreEqual(result, 4);
}
/// <summary>
/// 测试Add方法
/// </summary>
[Test]
public void Add2()
{
BasicModule bm = new BasicModule();
int result = bm.Add(1, 2);
if (result != 5)
Assert.BugBool(true);
else
Assert.BugBool(false);
}
}
开发过程中遇到了一个问题,WinForm自带的进度条控件不支持列改色彩,就是说是随着系统主题的(windowsxp以上系统),后来实在没有办法只
好自己实现一个简单的进度条自定义控件,虽然丑了一点,但终于可以变红色了哈哈.附带下控件的代码:
Code
partial class AssionProgressBar : UserControl
{
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region 组件设计器生成的代码
/// <summary>
/// 设计器支持所需的方法 - 不要
/// 使用代码编辑器修改此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.SuspendLayout();
//
// AssionProgressBar
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Name = "AssionProgressBar";
this.Size = new System.Drawing.Size(244, 30);
this.ResumeLayout(false);
}
int min = 0; // 定义最小值变量,默认为0
int max = 100; // 定义最大值变量,默认为100
int val = 0; // 当前值,默认为0
Color BarColor = Color.Green; // 定义颜色,默认为绿色
protected override void OnResize(EventArgs e)
{
// Invalidate the control to get a repaint. this.Invalidate();
}
/// <summary>
/// 重写绘制方法
/// </summary>
/// <param name="e"></param>
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
SolidBrush brush = new SolidBrush(BarColor);
float percent = (float)(val - min) / (float)(max - min);
Rectangle rect = this.ClientRectangle; // Calculate area for drawing the progress.
rect.Width = (int)((float)rect.Width * percent); // Draw the progress meter.
g.FillRectangle(brush, rect); // Draw a three-dimensional border around the control.
Draw3DBorder(g); // Clean up.
brush.Dispose();
g.Dispose();
}
/// <summary>
/// 最小值
/// </summary>
public int Minimum
{
get { return min; }
set
{ // Prevent a negative value.
if (value < 0) { min = 0; } // Make sure that the minimum value is never set higher than the maximum value.
if (value > max)
{
min = value; min = value;
} // Ensure value is still in range
if (val < min) { val = min; } // Invalidate the control to get a repaint.
this.Invalidate();
}
}
//最大值
public int Maximum
{
get { return max; }
set
{ // Make sure that the maximum value is never set lower than the minimum value.
if (value < min) { min = value; } max = value; // Make sure that value is still in range.
if (val > max) { val = max; } // Invalidate the control to get a repaint.
this.Invalidate();
}
}
/// <summary>
/// 当前值
/// </summary>
public int Value
{
get { return val; }
set
{
int oldValue = val; // Make sure that the value does not stray outside the valid range.
if (value < min) { val = min; } else if (value > max) { val = max; } else { val = value; } // Invalidate only the changed area.
float percent; Rectangle newValueRect = this.ClientRectangle; Rectangle oldValueRect = this.ClientRectangle; // Use a new value to calculate the rectangle for progress.
percent = (float)(val - min) / (float)(max - min); newValueRect.Width = (int)((float)newValueRect.Width * percent); // Use an old value to calculate the rectangle for progress.
percent = (float)(oldValue - min) / (float)(max - min); oldValueRect.Width = (int)((float)oldValueRect.Width * percent); Rectangle updateRect = new Rectangle(); // Find only the part of the screen that must be updated.
if (newValueRect.Width > oldValueRect.Width) { updateRect.X = oldValueRect.Size.Width; updateRect.Width = newValueRect.Width - oldValueRect.Width; } else { updateRect.X = newValueRect.Size.Width; updateRect.Width = oldValueRect.Width - newValueRect.Width; } updateRect.Height = this.Height; // Invalidate the intersection region only.
this.Invalidate(updateRect);
}
}
/// <summary>
/// 进度条颜色
/// </summary>
public Color ProgressBarColor
{
get { return BarColor; }
set
{
BarColor = value; // Invalidate the control to get a repaint.
this.Invalidate();
}
}
/// <summary>
/// 绘制进度条
/// </summary>
/// <param name="g"></param>
private void Draw3DBorder(Graphics g)
{
int PenWidth = (int)Pens.White.Width; g.DrawLine(Pens.DarkGray, new Point(this.ClientRectangle.Left, this.ClientRectangle.Top),
new Point(this.ClientRectangle.Width - PenWidth, this.ClientRectangle.Top));
g.DrawLine(Pens.DarkGray, new Point(this.ClientRectangle.Left, this.ClientRectangle.Top),
new Point(this.ClientRectangle.Left, this.ClientRectangle.Height - PenWidth));
g.DrawLine(Pens.White, new Point(this.ClientRectangle.Left, this.ClientRectangle.Height - PenWidth),
new Point(this.ClientRectangle.Width - PenWidth, this.ClientRectangle.Height - PenWidth));
g.DrawLine(Pens.White, new Point(this.ClientRectangle.Width - PenWidth, this.ClientRectangle.Top),
new Point(this.ClientRectangle.Width - PenWidth, this.ClientRectangle.Height - PenWidth));
}
#endregion
}
partial class AssionProgressBar : UserControl
{
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region 组件设计器生成的代码
/// <summary>
/// 设计器支持所需的方法 - 不要
/// 使用代码编辑器修改此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.SuspendLayout();
//
// AssionProgressBar
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Name = "AssionProgressBar";
this.Size = new System.Drawing.Size(244, 30);
this.ResumeLayout(false);
}
int min = 0; // 定义最小值变量,默认为0
int max = 100; // 定义最大值变量,默认为100
int val = 0; // 当前值,默认为0
Color BarColor = Color.Green; // 定义颜色,默认为绿色
protected override void OnResize(EventArgs e)
{
// Invalidate the control to get a repaint. this.Invalidate();
}
/// <summary>
/// 重写绘制方法
/// </summary>
/// <param name="e"></param>
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
SolidBrush brush = new SolidBrush(BarColor);
float percent = (float)(val - min) / (float)(max - min);
Rectangle rect = this.ClientRectangle; // Calculate area for drawing the progress.
rect.Width = (int)((float)rect.Width * percent); // Draw the progress meter.
g.FillRectangle(brush, rect); // Draw a three-dimensional border around the control.
Draw3DBorder(g); // Clean up.
brush.Dispose();
g.Dispose();
}
/// <summary>
/// 最小值
/// </summary>
public int Minimum
{
get { return min; }
set
{ // Prevent a negative value.
if (value < 0) { min = 0; } // Make sure that the minimum value is never set higher than the maximum value.
if (value > max)
{
min = value; min = value;
} // Ensure value is still in range
if (val < min) { val = min; } // Invalidate the control to get a repaint.
this.Invalidate();
}
}
//最大值
public int Maximum
{
get { return max; }
set
{ // Make sure that the maximum value is never set lower than the minimum value.
if (value < min) { min = value; } max = value; // Make sure that value is still in range.
if (val > max) { val = max; } // Invalidate the control to get a repaint.
this.Invalidate();
}
}
/// <summary>
/// 当前值
/// </summary>
public int Value
{
get { return val; }
set
{
int oldValue = val; // Make sure that the value does not stray outside the valid range.
if (value < min) { val = min; } else if (value > max) { val = max; } else { val = value; } // Invalidate only the changed area.
float percent; Rectangle newValueRect = this.ClientRectangle; Rectangle oldValueRect = this.ClientRectangle; // Use a new value to calculate the rectangle for progress.
percent = (float)(val - min) / (float)(max - min); newValueRect.Width = (int)((float)newValueRect.Width * percent); // Use an old value to calculate the rectangle for progress.
percent = (float)(oldValue - min) / (float)(max - min); oldValueRect.Width = (int)((float)oldValueRect.Width * percent); Rectangle updateRect = new Rectangle(); // Find only the part of the screen that must be updated.
if (newValueRect.Width > oldValueRect.Width) { updateRect.X = oldValueRect.Size.Width; updateRect.Width = newValueRect.Width - oldValueRect.Width; } else { updateRect.X = newValueRect.Size.Width; updateRect.Width = oldValueRect.Width - newValueRect.Width; } updateRect.Height = this.Height; // Invalidate the intersection region only.
this.Invalidate(updateRect);
}
}
/// <summary>
/// 进度条颜色
/// </summary>
public Color ProgressBarColor
{
get { return BarColor; }
set
{
BarColor = value; // Invalidate the control to get a repaint.
this.Invalidate();
}
}
/// <summary>
/// 绘制进度条
/// </summary>
/// <param name="g"></param>
private void Draw3DBorder(Graphics g)
{
int PenWidth = (int)Pens.White.Width; g.DrawLine(Pens.DarkGray, new Point(this.ClientRectangle.Left, this.ClientRectangle.Top),
new Point(this.ClientRectangle.Width - PenWidth, this.ClientRectangle.Top));
g.DrawLine(Pens.DarkGray, new Point(this.ClientRectangle.Left, this.ClientRectangle.Top),
new Point(this.ClientRectangle.Left, this.ClientRectangle.Height - PenWidth));
g.DrawLine(Pens.White, new Point(this.ClientRectangle.Left, this.ClientRectangle.Height - PenWidth),
new Point(this.ClientRectangle.Width - PenWidth, this.ClientRectangle.Height - PenWidth));
g.DrawLine(Pens.White, new Point(this.ClientRectangle.Width - PenWidth, this.ClientRectangle.Top),
new Point(this.ClientRectangle.Width - PenWidth, this.ClientRectangle.Height - PenWidth));
}
#endregion
}
老规距最后来一张运行效果图:
我写的不是代码,是轮子!