【问题标题】:Testing properties with private setters使用私有设置器测试属性
【发布时间】:2016-08-24 15:18:05
【问题描述】:

目前在我的项目的一部分中存在如下领域对象:

public class Address
{
    public virtual string HouseName { get; set; }

    public virtual string HouseNumber { get; set; }

    public virtual string RoadName { get; set; }

    public virtual string Postcode { get; set; }

    public virtual string District { get; private set; }
}

District 属性是数据库中的一个计算列。由于数据访问提供者(实体框架)的要求,需要一个私有集。这在正常的程序流程中很好,因为永远不需要设置地区,因为在数据库中保存/更新地址记录时会更新它

我要测试的方法如下所示:

public IEnumerable<House> GetHousesWithinSameDistrict (int addressId)
{
    var addressToMatch = _addressRepository
      .FirstOrDefault(address => address.Id == addressId)

    return _houseRepository
      .Where(house => house.Address.District == addressToMatch.District)
}

当我尝试设置 addressToMatch 变量时,这给我带来了问题,因为我无法设置 District 属性,因此我无法编写测试来检查是否返回了正确匹配的地址。

我应该如何为此测试设置地址对象?

【问题讨论】:

  • 也许,protected internal + assembly:InternalsVisibleTo?
  • @DeblatonJean-Philippe 相关,但恕我直言,肯定没有重复。
  • @DeblatonJean-Philippe 根本不是那个副本。
  • 使它成为protected set 并使用setter 方法创建一个子类(作为testfixture 的私有类)是一种(不是很漂亮但实用的)解决方法。
  • 没有看到你的测试很难给出建议,但是你可以使用你需要匹配的地址的Mock,并使用SetupGet返回你想要的值,你可以设置您需要使用反射的值,或者如果您使用 MS 测试框架,您可以使用 PrivateObject 设置值。 msdn.microsoft.com/en-us/library/ms244100.aspx

标签: c# unit-testing moq encapsulation access-modifiers


【解决方案1】:

首先,一个大胆的猜测:可能是声明您的 District 属性为 protected internal 加上向您的“域”程序集添加 assembly:InternalsVisibleTo 属性的组合,以便可以从您的测试中设置 Distinct

class Address
{
    public virtual string District { get; protected internal set; }
}

或者,您可以向Address 类添加一个内部构造函数,该构造函数将设置District 属性的值。再次,用assembly:InternalsVisibleTo 注释您的“域”程序集。

【讨论】:

  • 是否有替代使用 InternalsVisibleTo 的方法?它使我的代码有点混乱和不清楚(我正在练习 ddd,所以我的类中设置的所有属性都是私有的),如果你能告诉我一些更优雅的解决方案,我将不胜感激。谢谢
【解决方案2】:

如果您使用的是最小起订量(问题被标记,所以我假设您是),这可以开箱即用:

var mockAddress = new Mock<Address>();
mockAddress.SetupGet(p => p.District).Returns("Whatever you want to match");

所以一个更完整的例子是:

var mockAddress = new Mock<Address>();
mockAddress.SetupGet(p => p.Id).Returns(42);
mockAddress.SetupGet(p => p.District).Returns("What you want to match");

var mockAddressRepository = new Mock<IRepository<Address>>();
var addresses = new List<Address> { mockAddress.Object };
mockAddressRepository.Setup(p => p.GetEnumerator()).Returns(addresses.GetEnumerator());

var addressToMatch = mockAddressRepository.Object.FirstOrDefault(address => address.Id == 42);
Console.WriteLine(addressToMatch.District);

这会输出期望值:

What you want to match

【讨论】:

  • 这个答案真是太棒了。我正要使我的属性内部化并设置 InternalsVisibleTo。或者我打算使用 PrivateObject。这个答案是如此简单和美好。谢谢。
猜你喜欢
  • 1970-01-01
  • 2015-03-21
  • 2015-11-02
  • 1970-01-01
  • 2018-07-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多