【问题标题】:Faking all instances of every parent using Typemock使用 Typemock 伪造每个父级的所有实例
【发布时间】:2017-09-03 01:54:42
【问题描述】:

我最近开始使用 Typemock 并查看了至少六个现有线程,但似乎无法找到我确切问题的答案。

我有一个派生自 B 的类 C,它本身派生自 A。C 的实例是我需要测试的,因此需要是真实的。但由于 C 派生自 B(间接派生自 A),因此我需要在创建 C 的实例时完全自动伪造这两个类。

见下文:

class A
{
    protected int methodA()
    {
        return 1;
    }
}

class B : A
{
    protected int methodB()
    {
        return 5;
    }
}

class C : B
{
    public int methodC()
    {
        return methodA() * methodB();
    }
}

class Test
{
    public Test()
    {
        A fake_A = Isolate.Fake.AllInstances<A>(Members.ReturnRecursiveFakes, ConstructorWillBe.Ignored);
        Isolate.NonPublic.WhenCalled(fake_A, "methodA").DoInstead((MethodCallContext ctx) =>
            {
                return 2;
            }
        );

        B fake_B = Isolate.Fake.AllInstances<B>(Members.ReturnRecursiveFakes, ConstructorWillBe.Ignored);
        Isolate.NonPublic.WhenCalled(fake_B, "methodB").DoInstead((MethodCallContext ctx) =>
            {
                return 10;
            }
        );

        C c = new C(); // Would expect A and B to be faked automatically since I've faked all instances above. 
        int method_c_val = c.methodC(); // I get back 5, but what I need returned is 20.
    }
}

这是我所面临问题的一​​个极其简化的版本。这不仅仅是在父类中伪造一两个方法的行为。需要伪造整个父级层次结构。所以 A 和 B 都需要完全伪造,而不是部分伪造。

我已经看过的线程之一是这个,但那里的答案指向一个不再可用的地址:

https://www.typemock.com/answers/11613/mocking-all-instances-of-a-base-class

【问题讨论】:

  • 为了系统测试而模拟应用程序的某些部分是很糟糕的,模拟一个单个对象aspects听起来是个糟糕的主意。如果你真的必须这样做,我建议你重构为 composition pattern
  • 您能否详细说明为什么这是一个糟糕的主意?链接到文章、讨论、另一个线程、博客、支持你的声明的东西(任何东西)?不是说我不相信你,但有些例子会大有帮助......
  • 因为您的课程不是为此目的而设计的。你所拥有的只是一组没有设计模式的方法。推荐“四人帮”的设计模式书。祝你好运
  • 我正在处理遗留代码,这限制了我的选择。
  • 我在评论您在上面发布的内容不是我看不到的内容。如果您的实际代码与上述意图不同,那么任何解决您困境的讨论都将是无关紧要的

标签: c# typemock


【解决方案1】:

正如@Nkosi 建议的那样,您可以使用:

C c = Isolate.Fake.Instance<C>(Memebers.CallOriginal);
Isoalte.NonPublic.WhenCalled(c,"methodA").WillReturn(2);
Isoalte.NonPublic.WhenCalled(c,"methodB").WillReturn(10);

你伪造了 C 对象,但它的方法仍然调用原始实现(如果需要),并且你只伪造了有问题的方法。

【讨论】:

  • 我已经编辑了我的问题。基本上,这不仅仅是几个方法的伪造行为问题......这只是一个例子,证明我已经尝试过的方法(使用 fakeAll)不起作用。我所面临的实际情况相当复杂,我需要伪造整个 A 和 B,而不仅仅是部分。
  • 是的,但这取决于您要测试什么。在这种情况下,从基类继承的方法由对象 C 调用,而不是由 A 或 B 调用,因此伪造它们并且它们的方法与 C 对象无关。
【解决方案2】:

我不熟悉 typemock,但如果您无法获得答案、控制有问题的代码并能够修改它,我可以建议另一种可能的解决方法。

制作有问题的方法virtual,赋予派生类覆盖它们的能力。

class A
{
    protected virtual int methodA()
    {
        return 1;
    }
}

class B : A
{
    protected virtual int methodB()
    {
        return 5;
    }
}

class C : B
{
    public int methodC()
    {
        return methodA() * methodB();
    }
}

要单独测试 methodC,您可以创建一个派生自 C 的存根类 D,它会覆盖相关方法。

class D : C
{
    protected override int methodA()
    {
        return 2;
    }

    protected override int methodB()
    {
        return 10;
    }
}

这样,测试将按预期执行。

[TestClass]
public class Test
{
    [TestMethod]
    public void TestMethodC()
    {
        //Arrange
        var expected = 20;
        var c = new D();

        //Act
        int actual = c.methodC();

        //Assert
        Assert.AreEqual(expected, actual);
    }
}

我认为使用 typemock 你需要通过伪装C 来做类似的事情,并且只隔离有问题的两个依赖方法,让被测方法自然调用。但是我又不是很熟悉那个框架。

【讨论】:

  • 是的,这可以在您一开始提到的环境中工作,但即便如此,创建(本质上是)一种解决方法也需要大量代码。这只是一个非常简化的例子。即使我可以编辑 A 和 B 的代码(我不能),A 和 B 的实际类也是怪物。要进行真正的隔离测试,我必须在每个类中覆盖更多的方法。这就是 Typemock 的用武之地。它让我可以(递归地)将所有方法伪装成它们的默认原始值,并且我可以让我的 mock 在特定位置展示自定义行为,例如方法。
猜你喜欢
  • 1970-01-01
  • 2014-09-10
  • 2017-08-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-01
相关资源
最近更新 更多