How do I unit test errors in an IDataErrorInfo business object?
-
23-09-2019 - |
문제
I am writing (attempting to write) unit tests for a WPF application.
The business objects that the UI binds to implement IDataErrorInfo, such that when I set ValidatesOnDataErrors=True in my View xaml, the error indexer (this[]) is called anytime the setter for the bound business object is called. That part is great.
Now if I call that same property's setter from a unitTest, it never calls the error indexer. How do I force the IDataErrorInfo indexer to be evaluated from within a unit test?
just for illustration, here is one of my simple error indexers that contains a Name property. Setting 'myObject.Name = string.Empty;' does call the setter, but not the error indexer when I do this in my unit tests.
public string Name
{
get { return _name; }
set
{
_name = value;
IsDirty = true;
OnPropertyChanged("Name");
}
}
#region IDataErrorInfo
public Dictionary<string, string> ErrorCollection;
public string this[string property]
{
get
{
string msg = null;
switch (property)
{
case "Name":
if (string.IsNullOrEmpty(Name))
msg = "ICU Name is required.";
else if (Name.Length < 4)
msg = "ICU Name must contain at least 4 characters.";
else if (_parent.Units.AsEnumerable().Count(u => u.Name == Name) > 1)
msg = Name + " already exists, please change to a different Name.";
break;
}
if (msg != null && !ErrorCollection.ContainsKey(property))
ErrorCollection.Add(property, msg);
if (msg == null && ErrorCollection.ContainsKey(property))
ErrorCollection.Remove(property);
return msg;
}
}
public string Error
{
get { return null; }
}
#endregion
Thanks!
해결책
버전 2.1.0-M1 이후, Maven은 pom.xml에서 빌드 타임 스탬프를 얻으려면 특별 구문을 지원하고 doc 여기가 있습니다 :
<project>
...
<properties>
<maven.build.timestamp.format>yyyyMMdd.HHmmss</maven.build.timestamp.format>
</properties>
...
</project>
.
다른 팁
You need to hook into the PropertyChanged
event yourself and then when your handler is called, call the indexer with the property name. Or don't hook into the event and call the indexer with the name of the property you're testing.
That's what .NET does. It calls the indexer with property names.
MyClass mc = new MyClass();
mc.Name = "abc";
string error = mc["Name"];
The following NUnit tests called the indexer for the Name property and validate the Error message.
[TestFixture]
public class MyClassTests
{
[TestCase("", "ICU Name is required.")]
[TestCase("A Valid Name", null)]
public void ValidationIcuNameIsRequired(string name, string expectedResult)
{
// Arrange
var systemUnderTest = new MyClass();
// Act
systemUnderTest.Name = name;
// Assert
Assert.AreEqual(expectedResult, systemUnderTest[nameof(systemUnderTest.Name)]);
}
[TestCase("a", "ICU Name must contain at least 4 characters.")]
[TestCase("ab", "ICU Name must contain at least 4 characters.")]
[TestCase("abc", "ICU Name must contain at least 4 characters.")]
[TestCase("abcd", null)]
[TestCase("abcde", null)]
public void ValidationIcuNameLongerThanThreeCharacters(string name, string expectedResult)
{
// Arrange
var systemUnderTest = new MyClass();
// Act
systemUnderTest.Name = name;
// Assert
Assert.AreEqual(expectedResult, systemUnderTest[nameof(systemUnderTest.Name)]);
}
[Test]
public void ValidationParentDoesNotExist()
{
// Arrange
var systemUnderTest = new MyClass();
string icuName = "TestName";
systemUnderTest.Parent.Units.Add(new Unit() {Name = icuName });
// Act
systemUnderTest.Name = icuName;
// Assert
Assert.AreEqual(icuName + " already exists, please change to a different Name.", systemUnderTest[nameof(systemUnderTest.Name)]);
}
}