Moq:如何模拟不可见的类?
我有以下简化的代码来描述我的问题:
public interface IMyUser
{
int Id { get; set; }
string Name { get; set; }
}
它在数据访问层中使用,如下所示:
public interface IData
{
T GetUserById<T>(int id) where T : IMyUser, new();
}
userlogic 类定义如下:
public class UserLogic
{
private IData da;
public UserLogic(IData da)
{
this.da = da;
}
public IMyUser GetMyUserById(int id)
{
return da.GetUserById<MyUser>(id);
}
}
userlogic 使用仅在内部可见的 MyUSer 类。
我想使用 Moq 来模拟对数据访问层的调用。但因为我无法从我的单元测试代码(按设计)访问 MyUser 类,我不知道如何设置最小起订量?
起订量代码应该类似于:
var data = new Mock<IData>();
data.Setup(d => d.GetUserById<MyUser ???>(1)).Returns(???);
var logic = new UserLogic(data.Object);
var result = logic.GetMyUserById(1);
如何解决这个问题?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
让我扩展一下 Sjoerd 的答案。您面临的问题是由于无法从测试程序集中访问
MyUser
类型。使用InternalsVisibleTo
程序集属性可以轻松解决该问题。不过,我建议重新考虑您的设计并摆脱
IMyUser
接口,而只使用MyUser
类(应该是公共的)。通常,您将服务放在接口后面,而不是实体后面。提供IMyUser
的多种实现有什么好的理由吗?看看这个实现有多干净:
如果您坚持使用
IMyUser
接口及其内部实现,还有另一种解决方案。如果我正确推断IData.GetUserById
的内容,您现有的解决方案将如下所示:上面的代码稍微违反了 SRP(警告,PDF) 并混合了两个职责 - 从持久存储中检索实体并创建实体的实例。不仅如此,它还将创建责任放在了界面上,这就更糟糕了。
使用 Abstract Factory 和 依赖注入(PDF) 模式将带来更加简洁的设计,不会遇到与以前相同的问题。
Let me just expand on Sjoerd's answer. The problem you are facing is due to not being able to access
MyUser
type from the test assembly. That problem is easily fixed withInternalsVisibleTo
assembly attribute.I would however recommend to rethink your design and get rid of
IMyUser
interface and instead just useMyUser
class (which should be public). Normally you put services behind interfaces, not entities. Are there any good reasons for providing multiple implementations ofIMyUser
?Have a look at how much cleaner this implementation is:
There is another solution, if you insist on having
IMyUser
interface and its internal implementation. Your existing solution, if I infer the contents ofIData.GetUserById<T>
correctly, goes something like this:The above code is a slight violation of SRP(warning, PDF) and mixes two responsibilities - retrieving an entity from persistent storage and creating an instance of the entity. Not only that, it also puts the creation responsibility on the interface, which is even worse.
Decoupling those responsibilities using Abstract Factory and Dependency Injection(PDF) patterns will lead to much cleaner design that does not suffer from the same problem as before.
你不能
用
Can't you use
instead of
如果我想隐藏功能但让它可测试,我会将函数声明为
internal
,然后在文件顶部添加[ assembly: InternalsVisibleTo("MyAssemblyName" )]
属性,其中MyAssemblyName
是您要授予访问权限的单元测试程序集。谢谢 Stef 指出我之前的错误。If I want to hide functionality but let it be testable, I'll declare the functions as
internal
, and then at the top of the file I add the[assembly: InternalsVisibleTo("MyAssemblyName")]
attribute, whereMyAssemblyName
is the unit test assembly that you want to grant access to. Thanks, Stef, for pointing out my previous mistake.