如何为 windows 表单代码后面的方法编写单元测试
How to write unit test for method in back of windows form code
我有我想要测试的方法,但我得到了这个错误"Invoke or BeginInvoke cannot be called on a control until the window handle has been created."现在我还有一个列表框,它被填充到我正在测试的那个函数中。因此,当我将方法与另一个 class.
分开时,这是一个问题
我理解这一点,因为表格需要先 运行,但还有其他选择吗?
public partial class ImportForm : Form
{
public ImportForm()
{
}
public bool Test(string[] fileNames)//Method to test
{
foreach (DataTable table in result.Tables)
{
foreach (DataRow dr in table.Rows)
{
if (!db.CouncilRefundCases.Any(
c => c.RequestReference == dr.ItemArray[1].ToString()))
{
CouncilRefundCase data = new CouncilRefundCase()
{
FileId = fileId,
RequestReference = Convert.ToString(dr.ItemArray[1]),
CancelReason = Convert.ToString(dr.ItemArray[2]),
ProcessStatusId = (int?)ProcessStatus.Unprocessed,
ProcessDescription = new EnumHelper().GetDescription(ProcessStatus.Unprocessed),
DateCaptured = DateTime.Now
};
db.CouncilRefundCases.InsertOnSubmit(data);
//Succeeded ones
var item = new ListViewItem(dr.ItemArray[1].ToString());
lstSuccessSummary.Invoke((Action)delegate
{
lstSuccessSummary.Items.Add(item);
});
}
else
{
//Failed ones
var item = new ListViewItem(dr.ItemArray[1].ToString());
lstSummary.Invoke((Action)delegate
{
lstSummary.Items.Add(item);
});
}
}
}
return true;
}
}
这是我的单元测试
[TestMethod]
public void TestTest()
{
bool results=false;
var files = new string[4];
files[0] = @"filename1.xlsx";
files[1] = @"filename2.xlsx";
ImportForm form= new ImportForm();
results = form.Test(files);
Assert.AreEqual(true, results);
}
如果没有实际代码很难判断,但通常这表明 Test
方法中的代码不应该在表单中。
表单实际上应该只是显示逻辑,而不是模型逻辑。
Now I also have a list box that is being populated inside that
function I am testing. So its an issue when I separate the Method to
another class.
如果您用一些代码描述问题,我们可能会提供帮助。您可以使用事件或委托来解决它,以将视图逻辑排除在模型之外,反之亦然。
注意 - 在您阅读答案之前
一般来说,将 UI 代码和业务逻辑紧密耦合并不是一个好主意,但是如果您遇到无法重构以与 UI 分离的代码,您可以使用以下解决方案解决问题。
问题与解决方案
在显示窗体之前,窗体及其控件未处于 Created
状态,您不能使用窗体或其控件的 Invoke
方法。
要解决该问题,您可以强制创建窗体及其控件。为此,调用表单的内部 CreateControl(bool fIgnoreVisible)
方法并将 true
作为参数传递给它就足够了:
var f = new Form1();
var createControl = f.GetType().GetMethod("CreateControl",
BindingFlags.Instance | BindingFlags.NonPublic);
createControl.Invoke(f, new object[] { true });
备选方案
在调用方法之前显示 Form
。然后该表单将在 运行 单元测试期间显示。
在 STA
线程中显示 Form
。
例子
假设您的表单中有这样的方法:
public partial class Form1 : Form
{
//...
public int Method1(int i)
{
this.Invoke(new Action(() => { i++; }));
return i;
}
}
然后在你的测试项目中,可以使用如下代码:
[TestMethod]
public void TestMethod1()
{
var f = new Form1();
var createControl = f.GetType().GetMethod("CreateControl",
BindingFlags.Instance | BindingFlags.NonPublic);
createControl.Invoke(f, new object[] { true });
var input = 0;
var expected = 1;
var actual = f.Method1(input);
Assert.AreEqual(expected, actual);
}
我有我想要测试的方法,但我得到了这个错误"Invoke or BeginInvoke cannot be called on a control until the window handle has been created."现在我还有一个列表框,它被填充到我正在测试的那个函数中。因此,当我将方法与另一个 class.
分开时,这是一个问题我理解这一点,因为表格需要先 运行,但还有其他选择吗?
public partial class ImportForm : Form
{
public ImportForm()
{
}
public bool Test(string[] fileNames)//Method to test
{
foreach (DataTable table in result.Tables)
{
foreach (DataRow dr in table.Rows)
{
if (!db.CouncilRefundCases.Any(
c => c.RequestReference == dr.ItemArray[1].ToString()))
{
CouncilRefundCase data = new CouncilRefundCase()
{
FileId = fileId,
RequestReference = Convert.ToString(dr.ItemArray[1]),
CancelReason = Convert.ToString(dr.ItemArray[2]),
ProcessStatusId = (int?)ProcessStatus.Unprocessed,
ProcessDescription = new EnumHelper().GetDescription(ProcessStatus.Unprocessed),
DateCaptured = DateTime.Now
};
db.CouncilRefundCases.InsertOnSubmit(data);
//Succeeded ones
var item = new ListViewItem(dr.ItemArray[1].ToString());
lstSuccessSummary.Invoke((Action)delegate
{
lstSuccessSummary.Items.Add(item);
});
}
else
{
//Failed ones
var item = new ListViewItem(dr.ItemArray[1].ToString());
lstSummary.Invoke((Action)delegate
{
lstSummary.Items.Add(item);
});
}
}
}
return true;
}
}
这是我的单元测试
[TestMethod]
public void TestTest()
{
bool results=false;
var files = new string[4];
files[0] = @"filename1.xlsx";
files[1] = @"filename2.xlsx";
ImportForm form= new ImportForm();
results = form.Test(files);
Assert.AreEqual(true, results);
}
如果没有实际代码很难判断,但通常这表明 Test
方法中的代码不应该在表单中。
表单实际上应该只是显示逻辑,而不是模型逻辑。
Now I also have a list box that is being populated inside that function I am testing. So its an issue when I separate the Method to another class.
如果您用一些代码描述问题,我们可能会提供帮助。您可以使用事件或委托来解决它,以将视图逻辑排除在模型之外,反之亦然。
注意 - 在您阅读答案之前
一般来说,将 UI 代码和业务逻辑紧密耦合并不是一个好主意,但是如果您遇到无法重构以与 UI 分离的代码,您可以使用以下解决方案解决问题。
问题与解决方案
在显示窗体之前,窗体及其控件未处于 Created
状态,您不能使用窗体或其控件的 Invoke
方法。
要解决该问题,您可以强制创建窗体及其控件。为此,调用表单的内部 CreateControl(bool fIgnoreVisible)
方法并将 true
作为参数传递给它就足够了:
var f = new Form1();
var createControl = f.GetType().GetMethod("CreateControl",
BindingFlags.Instance | BindingFlags.NonPublic);
createControl.Invoke(f, new object[] { true });
备选方案
在调用方法之前显示
Form
。然后该表单将在 运行 单元测试期间显示。在
STA
线程中显示Form
。
例子
假设您的表单中有这样的方法:
public partial class Form1 : Form
{
//...
public int Method1(int i)
{
this.Invoke(new Action(() => { i++; }));
return i;
}
}
然后在你的测试项目中,可以使用如下代码:
[TestMethod]
public void TestMethod1()
{
var f = new Form1();
var createControl = f.GetType().GetMethod("CreateControl",
BindingFlags.Instance | BindingFlags.NonPublic);
createControl.Invoke(f, new object[] { true });
var input = 0;
var expected = 1;
var actual = f.Method1(input);
Assert.AreEqual(expected, actual);
}