我正在为一个类(类A)编写单元测试,该类以另一个类(类B)作为参数,而该类又将另一个类(类C)作为其参数。我需要模拟B类以测试A类。但是,模拟不采用类参数。
因此,我创建了一个特征(trait BsTrait),并且我的班级B扩展了BsTrait。根据此答案-(ScalaMock. Mock a class that takes arguments)。
我要测试的班级-class A(b: BsTrait){}
B类-class B(c: C){}
C级-class C{}
B类特征-trait BsTrait{}
我的单元测试-
val mockFactory = mockFunction[C, B]
val mockClient = mock[BsTrait]
mockFactory.expects(new C).returning(mockClient)```
Error: /path/to/file/Test.scala:63: type mismatch; found : com.example.BsTrait required: com.example.B
mockFactory.expects(new C).returning(mockClient)
我也尝试为模拟函数添加返回类型,但是它抛出了相同的错误。
答案 0 :(得分:0)
我知道这不是直接解决方案,也许实际上是。
以我的经验,在99%的情况下放弃了该模拟框架,而只是编写特征(或其他语言的接口)的模拟实现。是的,感觉就像样板,但是:
通常结果是,您编写的代码更少-模拟代码开始时很短,但是几乎总是开始进行各种变通,以允许进行各种调用,有时甚至调用您的测试也不在乎关于,但必须在那里。仅仅为了测试,您将要进行很多测试
一旦您在框架中模拟了具有某些测试行为的函数/方法,人们通常就不会发现何时不再需要进行测试,而忘记删除它。没什么警告我们的死代码已经死了
您控制的代码更容易扩展或修改以满足您的需求。您自己的问题就是一个很好的例子。如果您的模拟课程只是一堂课,您将不需要提问。现在,您的模拟隐藏了各种反射,也许是字节代码操作(我不知道ScalaMock是否做到了,但是很多框架都做到了),最有可能是其他令人讨厌的事情,这是无法调试的。
有名的模拟游戏通常很难维护。如果将一种方法添加到特征中,则即使不需要影响测试,也可能需要更新很多测试。只是因为这些测试以某种隐藏方式使用了它们
通过测试如何实现函数/方法而不是实现方法,您不会陷入模拟框架的陷阱。 (例如,重要的是让您的客户端专门调用名为get
的方法,还是执行get请求很重要,无论它是否调用exchange
,get
之类的东西其他吗?)
因此,即使感觉像是过分杀伤,还是要考虑还是这么做。从长远来看,您极有可能编写更少的代码。您编写的代码更加清晰易读,如果不再使用函数或方法,则可以将其从特征中删除,并在模拟中得到编译器警告。您的问题将自动得到解决,因为您只需扩展模拟的行为就足以使其继续进行。而且您更有可能实际编写好的测试。
最后,如果您遵循此建议,则只有一件事:保持模拟独立。不要让B在模拟中采用参数C。使您的B可以使用列表,地图或任何您需要的东西。重点是测试A,而不是B和C:)