Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.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/1/typo3/2.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
.net 为什么';Moq是否运行重写的ToString方法?_.net_Moq_Mocking - Fatal编程技术网

.net 为什么';Moq是否运行重写的ToString方法?

.net 为什么';Moq是否运行重写的ToString方法?,.net,moq,mocking,.net,Moq,Mocking,在下面的代码中,为什么mockTest.ToString()返回Null 编辑:在示例代码中添加注释以显示如何解决问题 Public Sub Main() Try Dim test = New TestClass If test.ToString <> "stackoverflow rules" Then Throw New Exception("Real Failed: Actual value: <" +

在下面的代码中,为什么mockTest.ToString()返回Null

编辑:在示例代码中添加注释以显示如何解决问题

Public Sub Main()

    Try

        Dim test = New TestClass

        If test.ToString <> "stackoverflow rules" Then
            Throw New Exception("Real Failed: Actual value: <" + test.ToString + ">")
        End If

        Dim mock = New Moq.Mock(Of TestClass)()
        mock.SetupGet(Function(m As TestClass) m.Name).Returns("mock value")

        ' As per Mark's accepted answer this is the missing line of 
        ' of code to make the code work.
        ' mock.CallBase = True

        Dim mockTest = DirectCast(mock.Object, TestClass)

        If mockTest.ToString() <> "mock value" Then
            Throw New Exception("Mock Failed: Actual value: <" + mockTest.ToString + ">")
        End If

        Console.WriteLine("All tests passed.")

    Catch ex As Exception

        Console.ForegroundColor = ConsoleColor.Red
        Console.WriteLine(ex.ToString)
        Console.ForegroundColor = ConsoleColor.White

    End Try

    Console.WriteLine()
    Console.WriteLine("Finished!")
    Console.ReadKey()

End Sub

Public Class TestClass

    Public Sub New()
    End Sub

    Public Overridable ReadOnly Property Name() As String
        Get
            Return "stackoverflow rules"
        End Get
    End Property

    Public Overrides Function ToString() As String
        Return Me.Name
    End Function

End Class
Public Sub-Main()
尝试
Dim test=新的TestClass
如果test.ToString“stackoverflow规则”,则
抛出新异常(“实际失败:实际值:”)
如果结束
Dim mock=新的Moq.mock(属于TestClass)()
SetupGet(函数(m作为TestClass)m.Name)。返回(“模拟值”)
根据马克接受的答案,这是一行缺失的
'的代码,使代码工作。
'mock.CallBase=True
Dim mockTest=DirectCast(mock.Object,TestClass)
如果mockTest.ToString()为“mock value”,则
抛出新异常(“模拟失败:实际值:”)
如果结束
Console.WriteLine(“所有测试均通过”)
特例
Console.ForegroundColor=ConsoleColor.Red
控制台写入线(例如ToString)
Console.ForegroundColor=ConsoleColor.White
结束尝试
Console.WriteLine()
Console.WriteLine(“完成!”)
Console.ReadKey()
端接头
公共类TestClass
公共分新()
端接头
作为字符串的公共可重写只读属性名()
得到
返回“堆栈溢出规则”
结束
端属性
Public将函数ToString()重写为字符串
告诉我你的名字
端函数
末级

因为您没有告诉它返回任何其他内容。您依赖于ToString方法的内部工作来返回name属性的值,但是ToString方法本身正在被模拟


我认为您需要将mock的
CallBase
属性设置为
true
,以指定在base对象上实际执行意外的方法调用。

TestClass上的Name属性和ToString方法都是虚拟的/可重写的,这意味着Moq将模拟它们

默认情况下,Moq为具有引用类型返回类型的成员返回null,除非您明确告诉它返回其他内容。因为字符串是引用类型,所以它返回null

您可以通过将CallBase设置为true来修复它

如果未明确定义覆盖,则将CallBase设置为true将导致Moq调用基本实现:

mock.CallBase = True

在这种情况下,这将指示mock使用ToString的基本实现,因为不存在eplicit设置(因此调用Name属性,它确实有一个设置)。

问题的根源实际上是您正在模拟您正在测试的内容

这是这些问题最常见的原因。mock设计用于隔离您真正想要测试的内容,而不是您想要测试的内容

您应该直接测试此方法,并模拟它可能具有的任何依赖项,而不是尝试测试自身的对象


您应该使用部分模拟的唯一原因(这是设置CallBase允许您执行的操作)如果您正在使用的类是抽象的,并且您希望测试抽象类的功能,即使您没有实现类。

上述解决方案仅在您不尝试模拟ToString()方法返回的内容时有效。 例如,如果我要使用上述类的存根来测试另一个类,我需要能够指定调用ToString()后它返回的内容。不幸的是,即使使用了

stub.Setup(s=>s.ToString())。返回(“fakevalue”)

Moq仍将返回自己的ToString()覆盖(“CastleProxies…”)。 另一方面,如果我
stub.CallBase=true

它也不会使用我的设置

我找到的解决方案不是一起使用ToString(),而是引入一个属性,例如Name,我的类现在将使用它来代替ToString(),并且我可以很容易地进行设置

为了保留ToString()的功能,我只使用了
returnname在那里


有时候,做一些与平时稍有不同的事情会更容易,从而避免很多头痛;)

我的解决方案是创建一个定义ToString的虚拟接口,并添加一个扩展方法,使在ToString上设置Expections更加容易:

public static class MoqExtensions
{
    public static ISetup<IToStringable, string> SetupToString<TMock>(this Mock<TMock> mock) where TMock : class
    {
        return mock.As<IToStringable>().Setup(m => m.ToString());
    }

    //Our dummy nested interface.
    public interface IToStringable
    {
        /// <summary>
        /// ToString.
        /// </summary>
        /// <returns></returns>
        string ToString();
    }
}
公共静态类MoqExtensions
{
公共静态ISetup SetupToString(此模拟),其中TMock:class
{
返回mock.As().Setup(m=>m.ToString());
}
//我们的虚拟嵌套接口。
可串接的公共接口
{
/// 
///托斯特林。
/// 
/// 
字符串ToString();
}
}
然后,您可以像这样使用扩展方法:

[Test]
public void ExpectationOnToStringIsMet()
{
    var widget = new Mock<IWidget>();
    widget.SetupToString().Returns("My value").Verifiable();

    Assert.That(widget.Object.ToString(), Is.EqualTo("My value"));

    widget.Verify();
}
[测试]
公共无效预期字符串集()
{
var widget=newmock();
SetupToString()返回(“我的值”).Verifiable();
Assert.That(widget.Object.ToString(),是.EqualTo(“我的值”);
widget.Verify();
}

但他正在执行一个
mock.SetupGet(Function(m As TestClass)m.Name)。返回(“mock value”)
-不应该这样做吗?不,因为他依赖于他的
ToString
实现来访问
Name
属性,这不会发生,因为模拟中的
ToString
方法已被替换。谢谢。解释得很好。“这似乎是一种奇怪的默认行为,”安德森说。对不起,我想我不明白你的答案。为了发布问题,我给出的示例代码过于简单。导致我提出这个问题的原因是我有一个performance stopwatch类,其中ToString方法格式化了运行时间以用于日志记录。我需要根据不同的时间长度检查结果的格式。在本例中,测试ToString方法的唯一原因不是对运行时间进行部分模拟并将CallBase设置为true吗?在您的例子中,我将测试一个帮助器方法,该方法执行