【发布时间】:2013-01-10 00:17:17
【问题描述】:
我刚刚开始深入研究单元测试,并且刚刚开始掌握存储库模式和 IoC。然而,我不认为我完全理解它,因为它的某些部分似乎有点傻。让我解释一下。
我的控制器:
public class UserProfileController : ApiController
{
private IUserProfileRepository repository;
// Optional constructor, passes repository, allows dependency injection
public UserProfileController(IUserProfileRepository userProfileRepository)
{
this.repository = userProfileRepository;
}
// GET api/UserProfile
// Returns a list of all users
public IEnumerable<UserProfile> Get()
{
// Only Admins can see a list of users
if (Roles.IsUserInRole("Admin"))
{
return repository.Get();
}
else
{
throw new HttpResponseException(
new HttpResponseMessage(HttpStatusCode.Forbidden)
{
ReasonPhrase = "Administrator access required"
});
}
}
// Other methods, etc.
(请注意,我有一个依赖,Roles.IsUserInRole("Admin") 我无法弄清楚如何抽象,这会导致一些问题)。
我的典型repo界面:
public interface IUserProfileRepository : IDisposable
{
IEnumerable<UserProfile> Get();
// Other methods, etc.
}
回购:
public class UserProfileRepository : IUserProfileRepository, IDisposable
{
private OfootContext context;
public UserProfileRepository(OfootContext context)
{
this.context = context;
}
public IEnumerable<UserProfile> Get()
{
return context.UserProfiles.AsEnumerable();
}
// ... More code
所以一切看起来都很好,我已经从我的业务逻辑中抽象了我的业务访问层,现在我可以创建一个假存储库来运行单元测试。
假回购:
public class FakeUserProfileRepository : IUserProfileRepository, IDisposable
{
private List<UserProfile> context;
public FakeUserProfileRepository(List<UserProfile> context)
{
this.context = context;
}
public IEnumerable<UserProfile> Get()
{
return context.AsEnumerable();
}
和测试:
[TestMethod]
public void GetUsers()
{
// Arrange
var items = new List<UserProfile>()
{
new UserProfile
{
UserId = 1,
Username = "Bob",
},
new UserProfile
{
UserId = 2,
Username = "Bob2",
}
};
FakeUserProfileRepository repo = new FakeUserProfileRepository(
items);
UserProfileController controller = new UserProfileController(
repo);
// Act
IEnumerable<UserProfile> result = controller.Get();
// Assert
Assert.IsNotNull(result);
}
既然我们在同一页面上(并且随时指出任何“代码味道”),以下是我的想法:
- 假存储库要求我重新实现所有实体框架逻辑并将其更改为处理 List 对象。这是我需要调试的更多工作和链条中的更多链接。
- 如果单元测试通过,它不会说明我的访问 EF 的代码,所以我的应用程序仍然可能失败。这只是意味着我需要单独测试我的 EF 代码并让它访问数据库。
- 从 #1 开始,如果单元测试没有测试 EF 代码,那么它只是在处理我的身份验证、授权和我的控制器中的用户创建代码。它不能,因为 WebSecurity 和 Roles 类访问了我的数据库。
- 如果我要使用数据库来测试 EF 代码(第 2 点)并且需要一个数据库来测试控制器代码(用于身份验证和授权,第 3 点),那么为什么还要费心使用存储库进行抽象。为什么我不直接抽象上下文(使用 IContext 或其他东西?)并连接到使用 DropCreateDatabaseAlways 类填充的测试数据库中?
如果我确实想出了一种方法来抽象出用户帐户垃圾,我仍然只是在改组代码并创建更多代码(甚至可能是两倍?因为我需要创建假货)我可以在其中替换 Context .
我的问题是:我错过了什么?它是一个整体概念还是特定的东西?
【问题讨论】:
标签: asp.net-mvc unit-testing asp.net-web-api repository-pattern