我的viewmodel中有一个属性,其唯一的工作是在属性更改时发送消息。我想进行单元测试,确实这样做了,所以我编写了以下测试
[TestFixture, RequiresSTA]
public class ToolBarViewModelTests
{
private SecondaryScalingMode _SecondaryScalingMode;
private void RecordSecondaryScalingSetting(SecondaryScalingMode obj)
{
_SecondaryScalingMode = obj;
}
[Test]
public void AssertCombineAllCornersScalingMessageIsSent()
{
var vm = CreateNewToolBar();
_SecondaryScalingMode = SecondaryScalingMode.IndividualCorner;
AppMessages.SetSecondaryScalingMode.Register(this, (Action<SecondaryScalingMode>)RecordSecondaryScalingSetting);
vm.CombineAllCornersScaling = true;
Assert.IsFalse(vm.IndividualCornerScaling);
Assert.IsFalse(vm.LeftRightScaling);
Assert.IsFalse(vm.FrontRearScaling);
Assert.IsTrue(vm.CombineAllCornersScaling);
Assert.AreEqual(SecondaryScalingMode.CombineAllCorners, _SecondaryScalingMode);
}
}
此测试断言正确的行为,但由于线程错误,它在本地和我的构建服务器上偶尔会失败。错误如下
Test(s) failed. System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation.
----> System.InvalidOperationException : The calling thread cannot access this object because a different thread owns it.
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
我是否有更好的方法来编写此测试,以防止它以这种方式随机失败?
答案 0 :(得分:1)
好的,这是我经常采取的方法。这与你的工作非常接近。 请记住,您还可以在单元测试中劫持Messenger并订阅Messenger。
我发布了一个简化版的代码,以便与示例相匹配。
我以前在单元测试中也有一些奇怪的错误,这是一个时间/线程问题......
因为它有助于重置Messenger foreach单元测试......
这是viewmodel(simplefied guess work =)...):
public class UnitTestViewModel:ViewModelBase
{
public UnitTestViewModel()
{
Messenger.Default.Register<string>(this, "SetSecondaryScalingMode", (message) =>
{
UpdateScalingMode();
});
}
private bool _CombineAllCornersScaling;
public bool CombineAllCornersScaling
{
get {
return _CombineAllCornersScaling;
}
set {
_CombineAllCornersScaling = value;
Messenger.Default.Send<string>("update", "SetSecondaryScalingMode");
RaisePropertyChanged("CombineAllCornersScaling");
}
}
private bool _IndividualCornerScaling;
public bool IndividualCornerScaling
{
get
{
return _IndividualCornerScaling;
}
set
{
_IndividualCornerScaling = value;
RaisePropertyChanged("IndividualCornerScaling");
}
}
private bool _LeftRightScaling;
public bool LeftRightScaling
{
get
{
return _LeftRightScaling;
}
set
{
_LeftRightScaling = value;
RaisePropertyChanged("LeftRightScaling");
}
}
private bool _FrontRearScaling;
public bool FrontRearScaling
{
get
{
return _FrontRearScaling;
}
set
{
_FrontRearScaling = value;
RaisePropertyChanged("FrontRearScaling");
}
}
private void UpdateScalingMode()
{
IndividualCornerScaling = false;
LeftRightScaling = false;
FrontRearScaling = true;
}
}
这是单元测试(使用MSTest但可以应用于其他包)...
[TestMethod]
public void UpdaetScalingMode()
{
Messenger.Reset();
var vm = new UnitTestViewModel();
bool updateMessageWasSend = false;
string _thisCanBeTheObjectYouWerePassing = String.Empty;
Messenger.Default.Register<string>(vm, "SetSecondaryScalingMode", (msg) =>
{
_thisCanBeTheObjectYouWerePassing = msg;
updateMessageWasSend = true;
});
vm.CombineAllCornersScaling = true;
Assert.AreEqual(true, updateMessageWasSend);
Assert.AreEqual(false, vm.IndividualCornerScaling);
Assert.AreEqual(false, vm.LeftRightScaling);
Assert.AreEqual(true, vm.CombineAllCornersScaling);
Assert.AreEqual("update", _thisCanBeTheObjectYouWerePassing);
}
Rember只是为了展示这个概念。
我刚刚传递了一个消息有效负载的字符串,但这可能与所有信使功能一样复杂....
我希望这会有所帮助......否则看看ViewModel代码与其他测试策略相结合会很有帮助...
P.S。:我还养成了每次测试只有1个断言并且编写更多测试的习惯......