加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – 在单元测试中将未经验证的添加属性断言给对象

发布时间:2020-12-15 21:49:04 所属栏目:百科 来源:网络整理
导读:我有MSTest(VS 2012)单元测试,我想断言对象的各种属性都有我想要的值.有很多方法可以做到这一点.但是我主要担心的是,如果向对象添加新属性,则很容易忽略更新单元测试以确保它具有我们期望的值. 我能想到的一件事是使用反射来枚举对象的公共属性,然后跟踪单元
我有MSTest(VS 2012)单元测试,我想断言对象的各种属性都有我想要的值.有很多方法可以做到这一点.但是我主要担心的是,如果向对象添加新属性,则很容易忽略更新单元测试以确保它具有我们期望的值.

我能想到的一件事是使用反射来枚举对象的公共属性,然后跟踪单元测试声明了哪些属性,最后断言是否有任何属性未被检查.

有没有人写过类似的东西?

有更好的想法吗?

更新:
我应该指出,所讨论的objedct类似于数据传输对象,其中有其他类/方法导致该对象中的数据被更新.很容易忽略更新这些类/方法的测试,以确保我们考虑所有对象的属性.我想要比右键单击对象,查找引用和查看代码更强一些(即不能忘记或忽略).

例如:

public class Person {
  public string FirstName;
}

public Person GetPerson() {}

[TestMethod]
public void GetPerson_ReturnsFilledInPerson()
{
    var actual = target.GetPerson();
    Assert.IsNotNull(actual.FirstName);
    // If somebody later adds LastName to Person,// we want this unit test to fail until the LastName is checked too.
}

谢谢,

解决方法

你所要求的并非不合理.对于简单的Domain类到DTO映射,您可以使用诸如Automapper之类的框架.您只需告诉它域类A映射到dto ADto,它将使用约定优于配置来映射属性.该框架还附带了一种测试您已完成所有映射的方法.你可以调用Mapper.AssertConfigurationIsValid();并且它将确保Dto中的每个属性都已映射到域类中的属性(通过具有相同的属性名称明确代码或隐含).

所以基本上你正在尝试做同样的事情,这就是为什么它是一个非常有效的场景.假设您选择不使用Automapper.我猜您在代码中没有单独的映射器(在这种情况下,您可以使用反射来测试映射器类/代码).我做了类似的事情,所有DTO都实现了返回另一个IDto的DeepCopy方法.但我们希望实际类型与调用类型相同

[Test]
    public void DeepCopyReturnsSameTypeAsOriginal()
    {
        var iDtoType = typeof (IDto);
        var allIDtoTypes = iDtoType.Assembly.GetTypes().Where(t => iDtoType.IsAssignableFrom(t) && t.IsClass && !t.IsAbstract).ToList();

        foreach (var currentIDtoType in allIDtoTypes)
        {
            var instanceOfDtoType = (IDto)Activator.CreateInstance(currentIDtoType);
            var deepCopyType = instanceOfDtoType.DeepCopy();
            Assert.AreEqual(instanceOfDtoType.GetType(),deepCopyType.GetType(),string.Format("Deep Copy of Type '{0}' does not return the same Type. It returns '{1}'. The DeepCopy method of IDto should return the same type.",instanceOfDtoType.GetType(),deepCopyType.GetType()));
        }
    }

您可以使用类似的逻辑来获取您的人物对象.获取person对象的所有公共属性并迭代它们并断言您返回的具体person对象包含该特定属性的非null值.

虽然在这种情况下,测试必须仅用于非常特定的对象,您知道所有属性必须具有非null值.例如,对于值类型,如果AccountBalance属性返回0,那么此人是否具有0余额或未设置属性?如果此人的电子邮件属性为null,这是否意味着它未映射,或者我们是否没有为系统中的人员发送电子邮件.这就是为什么如果您有特定的mapper类或使用Automapper,那么您更具体地测试该映射是否存在而不是“它是否具有值”,正如我所说,它可能仍适用于您的应用程序中的一些有限类.

另一种选择是装饰您知道的不能为null的属性,并且必须使用自定义属性进行映射.例如

Public class PersonDto {
    [TestNotNull]
    public string FirstName { get; set}

}

然后在单元测试中,您可以使用反射来查找具有此属性的所有属性,并确保它们不为空.但是,当然你遇到了你试图在不同层面解决的同样问题.如果您担心人们会忘记映射重要字段,则无法保证他们会记得使用自定义属性装饰这些字段.

当然,您可能不想测试该属性是否被映射,只是该属性存在.在这种情况下,使用反射来获取域对象类型的所有属性的列表,并确保它们中的每一个都存在于DTO对象类型的属性列表中.但这并不会测试属性本身是否被映射,只是它们存在.如果使用Automapper及其AssertConfigurationIsValid()测试,则测试DTO中的每个属性是否正确映射,而不是域中的每个属性都在DTO中具有关联属性.

因此,要回答您的问题,如果您要测试属性是否存在以及是否正确映射,则需要进行两次测试.一个用于比较域对象类型和Dto对象类型,并确保一个属性存在于另一个中,另一个测试用于确保DTO中的所有属性都映射到某个(无论您是否正在进行映射)在您自己的代码中或使用像Automapper这样的框架.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读