Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/291.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/apache-spark/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 验证对字典中索引属性的调用_C#_Dictionary_Dependency Injection_Mocking_Moq - Fatal编程技术网

C# 验证对字典中索引属性的调用

C# 验证对字典中索引属性的调用,c#,dictionary,dependency-injection,mocking,moq,C#,Dictionary,Dependency Injection,Mocking,Moq,我试图模拟一个包含字典的类,并验证对字典特定索引的调用 类的接口如下所示: public interface IClassWithADictionary { IDictionary<string, string> Dictionary { get; } } 带有词典的公共接口IClass { IDictionary字典{get;} } 这门课看起来像: public class ConcreteClassWithADictionary : IClassWithADicti

我试图模拟一个包含字典的类,并验证对字典特定索引的调用

类的接口如下所示:

public interface IClassWithADictionary
{
    IDictionary<string, string> Dictionary { get; }
}
带有词典的公共接口IClass
{
IDictionary字典{get;}
}
这门课看起来像:

public class ConcreteClassWithADictionary : IClassWithADictionary
{
    public ConcreteClassWithADictionary(IDictionary<string, string> dictionary)
    {
        Dictionary = dictionary;
    }

    public IDictionary<string, string> Dictionary { get; }
}
public class-ConcreteClassWithADictionary:IClassWithADictionary
{
带有词典(IDictionary dictionary)的公共具体类
{
字典=字典;
}
公共IDictionary字典{get;}
}
现在这里是我不明白的地方,我有一个测试用例,我试图验证字典中的特定键是否已设置,然后我试图验证是否已检索到该键

[Test]
public void MyTest()
{
    var concreteClassWithADictionaryMock = new Mock<IClassWithADictionary>();

    var dictionary = new Dictionary<string, string>();

    concreteClassWithADictionaryMock
        .Setup(m => m.Dictionary)
        .Returns(dictionary); // Setting up mock to return a concrete dictionary

    var key = "Key";
    var value = "Value";

    concreteClassWithADictionaryMock.Object.Dictionary[key] = value; // Setting the value
    var test = concreteClassWithADictionaryMock.Object.Dictionary[key]; // Getting the value

    // Passes here - no index specified
    concreteClassWithADictionaryMock.Verify(m => m.Dictionary);

    // Passes here - with VerifyGet() too
    concreteClassWithADictionaryMock.VerifyGet(m => m.Dictionary);

    // Fails here - throws exception, "Expression is not a property access: m => m.Dictionary[.key]"
    concreteClassWithADictionaryMock.VerifyGet(m => m.Dictionary[key]);

    //Fails here - no invocation performed, doesn't seem to like the set or the key indexer
    concreteClassWithADictionaryMock.VerifySet(m => m.Dictionary[key] = value);

    // Fails here - no invocation performed, even with verifying index access of some kind
    concreteClassWithADictionaryMock.Verify(m => m.Dictionary[key]);
}
[测试]
公共无效MyTest()
{
var concreteClassWithADictionaryMock=new Mock();
var dictionary=newdictionary();
带adictionarymock的混凝土类
.Setup(m=>m.Dictionary)
.Returns(dictionary);//设置mock以返回具体的dictionary
var key=“key”;
var value=“value”;
concreteClassWithADictionaryMock.Object.Dictionary[key]=value;//设置值
var test=concreteClassWithADictionaryMock.Object.Dictionary[key];//获取值
//在此处传递-未指定索引
concreteClassWithADictionaryMock.Verify(m=>m.Dictionary);
//在此传递-也使用VerifyGet()传递
concreteClassWithADictionaryMock.VerifyGet(m=>m.Dictionary);
//此处失败-引发异常,“表达式不是属性访问:m=>m.Dictionary[.key]”
带有adictionarymock.VerifyGet(m=>m.Dictionary[key])的具体类;
//此处失败-未执行任何调用,似乎不喜欢集合或键索引器
concreteClassWithADictionaryMock.VerifySet(m=>m.Dictionary[key]=value);
//此处失败-即使验证某种索引访问,也不会执行任何调用
验证(m=>m.Dictionary[key]);
}

显然,Moq框架可以验证字典本身的获取和设置,但不能验证特定的键或索引。我的问题是,;在模拟类中验证字典中特定键的获取和设置的正确方法是什么?

答案有些琐碎


您应该模拟mock类返回的字典,并对其调用verify方法。

有趣的是,我之前没有注意到它,但那已经是深夜了。基本上,卡梅隆是这么说的:你应该嘲笑IDictionary。原因如下:

var dictionary = new Dictionary<string, string>(); // <---- HEEERE

concreteClassWithADictionaryMock
    .Setup(m => m.Dictionary)
    .Returns(dictionary); // Setting up mock to return a concrete dictionary

// ...

concreteClassWithADictionaryMock.Verify(m => m.Dictionary); // A

concreteClassWithADictionaryMock.VerifyGet(m => m.Dictionary[key]); // B
接下来,是什么执行录制?不,当然是正常的典型课程。所有的模拟都是用来录音的

mConcrete.Dictionary[key] :
1)  mock    get_Dictionary  (property getter)    <-- 'm' records the call
                                                     and returns dict
                                                     according to setup
注意,在最后一个示例中,我正在对dictionary mock进行验证。这是因为mConcrete仍然不知道除了它自己以外的任何其他对象上发生了什么

最后一点:Moq实际上支持动态创建“模拟对象图”。发件人:

//创建一个自动递归模拟:一个模拟,它将为每个没有期望且其返回值可以模拟的成员返回一个新的模拟(即,它不是值类型)
//默认DefaultValue是DefaultValue.Empty,即ref类型为NULL
//让我们改变这一点
var mock=new mock{DefaultValue=DefaultValue.mock};
//此属性访问通常会返回NULL
//但现在返回一个模拟酒吧
Bar值=mock.Object.Bar;
//返回的mock被重用,因此可以进一步访问返回的属性
//相同的模拟实例。这允许我们也使用这个实例来
//如果我们愿意,就对它设定进一步的期望
var barMock=Mock.Get(值);
Setup(b=>b.Submit()).Returns(true);

如果您有“嵌套”接口,比如这里的-IConcreteClass返回IDictionary(它确实返回IDictionary而不是Dictionary,对吗?:),那么您可以使用此功能使IDictionary模拟(以及任何内部)由Moq自动创建。

您使用的是实际的词典,而不是模拟的词典,因此Moq不知道已访问的词典的成员。我假设提供的示例代码片段仅用于演示目的,因为不应模拟被测主题。当然,抱歉,我应该澄清一下,测试用例并不能完全代表我的场景,这只是一个解释我误解的例子:)
mConcrete.Dictionary[key] :
1)  mock    get_Dictionary  (property getter)    <-- 'm' records the call
                                                     and returns dict
                                                     according to setup
mConcrete.Dictionary[key] :
1)  ...
2)  dict    get_Item        (aka. this[])       <-- plain Dict returns item
                                                    no recording happens
var mDictionary = new Mock<IDictionary<string, string>>();
mDictionary.Setup(d => d["key"]).Returns("value");

var mConcrete = new Mock<IClassWithADictionary>();
mConcrete
    .Setup(m => m.Dictionary)
    .Returns(mDictionary.Object); // Setting up mock to return a mock

var test = mConcrete.Object.Dictionary[key]; // Getting the value

// verify if the Dictionary-Itself was read
mConcrete.Verify(m => m.Dictionary);

// verify if the Dictionary-Contents was read
mDictionary.Verify(m => m.Dictionary["key"]);
// Make an automatic recursive mock: a mock that will return a new mock for every member that doesn't have an expectation and whose return value can be mocked (i.e. it is not a value type)

// default DefaultValue is DefaultValue.Empty, i.e. NULL of ref types
// let's change that

var mock = new Mock<IFoo> { DefaultValue = DefaultValue.Mock };

// this property access would normally return a NULL
// but now returns a mock of Bar
Bar value = mock.Object.Bar;

// the returned mock is reused, so further accesses to the property return 
// the same mock instance. this allows us to also use this instance to 
// set further expectations on it if we want
var barMock = Mock.Get(value);
barMock.Setup(b => b.Submit()).Returns(true);