微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何为没有公共构造函数的密封类创建固定装置?

如何解决如何为没有公共构造函数的密封类创建固定装置?

密封了一个没有构造函数的类,这是我使用 SDK 引用到我的项目。我想为类创建夹具数据来编写测试,但 AutoFixture 给出了如下期望。

AutoFixture was unable to create an instance from SealedTypeclass,most likely because it has no public constructor,is an abstract or non-public type.

请找到我正在尝试为其创建夹具的以下代码示例。

public sealed class TokenCacheItem
{
    public string Authority { get; }
    public string ClientId { get; }
    public DateTimeOffset ExpiresOn { get; }
    public string FamilyName { get; }
    public string Givenname { get; }
    public string IdentityProvider { get; }
    public string TenantId { get; }
}

对于上面密封的类,我是通过 SDK 引用的,我正在尝试创建夹具数据。我收到以下错误消息。

留言: AutoFixture.ObjectCreationExceptionWithPath :AutoFixture 无法从 *** 创建实例,很可能是因为它没有公共构造函数,是抽象或非公共类型。

任何通用的解决方案?

解决方法

鉴于它是密封的并报告它没有公共构造函数,您将不得不提供一种创建实例的方法,它可能是基于反射的解决方案。只读属性也增加了 AutoFixture 的复杂性。

没有看到构造函数,或者只读属性是否有任何支持字段,我将通过以下工作示例做出一些假设。

创建可以创建 TokenCacheItem 并设置其属性的内容:

public class MutableTokenCacheItem
{
    private TokenCacheItem _tokenCacheItem;

    public string Authority { get => _tokenCacheItem.Authority; set => SetPropertyValue(x => x.Authority,value); }
    public string ClientId { get => _tokenCacheItem.ClientId; set => SetPropertyValue(x => x.ClientId,value); }
    public DateTimeOffset ExpiresOn { get => _tokenCacheItem.ExpiresOn; set => SetPropertyValue(x => x.ExpiresOn,value); }
    public string FamilyName { get => _tokenCacheItem.FamilyName; set => SetPropertyValue(x => x.FamilyName,value); }
    public string GivenName { get => _tokenCacheItem.GivenName; set => SetPropertyValue(x => x.GivenName,value); }
    public string IdentityProvider { get => _tokenCacheItem.IdentityProvider; set => SetPropertyValue(x => x.IdentityProvider,value); }
    public string TenantId { get => _tokenCacheItem.TenantId; set => SetPropertyValue(x => x.TenantId,value); }

    public MutableTokenCacheItem()
    {
        var ctor = typeof(TokenCacheItem).GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic).Single();
        _tokenCacheItem = (TokenCacheItem)ctor.Invoke(null);
    }

    private void SetPropertyValue<P>(Expression<Func<TokenCacheItem,P>> expression,object value)
    {
        var body = expression.Body as MemberExpression;
        var backingField = typeof(TokenCacheItem).GetRuntimeFields().Where(a => Regex.IsMatch(a.Name,$"\\A<{body.Member.Name}>k__BackingField\\Z")).Single();
        backingField.SetValue(_tokenCacheItem,value);
    }

    public TokenCacheItem AsImmutableTokenCacheItem()
    {
        return _tokenCacheItem;
    }
}

创建一个样本构建器以将其很好地固定到 AutoFixture 中:

public class TokenCacheItemSpecimenBuilder : ISpecimenBuilder
{
    public object Create(object request,ISpecimenContext context)
    {
        var t = request as Type;
        if (typeof(TokenCacheItem).Equals(t))
        {
            var mutableTokenCacheItem = context.Create<MutableTokenCacheItem>();
            return mutableTokenCacheItem.AsImmutableTokenCacheItem();
        }

        return new NoSpecimen();
    }
}

添加自定义,然后开始:

var fixture = new Fixture();
fixture.Customizations.Add(new TokenCacheItemSpecimenBuilder());
fixture.Create<TokenCacheItem>();

工作 LINQPad 示例:

void Main()
{
    var fixture = new Fixture();
    fixture.Customizations.Add(new TokenCacheItemSpecimenBuilder());
    Console.Write(fixture.Create<TokenCacheItem>());
}

public class TokenCacheItemSpecimenBuilder : ISpecimenBuilder
{
    public object Create(object request,ISpecimenContext context)
    {
        var t = request as Type;
        if (typeof(TokenCacheItem).Equals(t))
        {
            var mutableTokenCacheItem = context.Create<MutableTokenCacheItem>();
            return mutableTokenCacheItem.AsImmutableTokenCacheItem();
        }

        return new NoSpecimen();
    }
}

public class MutableTokenCacheItem
{
    private TokenCacheItem _tokenCacheItem;

    public string Authority { get => _tokenCacheItem.Authority; set => SetPropertyValue(x => x.Authority,value);
    }

    public TokenCacheItem AsImmutableTokenCacheItem()
    {
        return _tokenCacheItem;
    }
}

public sealed class TokenCacheItem
{
    public string Authority { get; }
    public string ClientId { get; }
    public DateTimeOffset ExpiresOn { get; }
    public string FamilyName { get; }
    public string GivenName { get; }
    public string IdentityProvider { get; }
    public string TenantId { get; }

    private TokenCacheItem() { }
}

结果:

enter image description here

YMMV 取决于实际的 TokenCacheItem 实现,尽管它可能不远了。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?