我正在启动一个Web应用程序,它将使用asp.net会员服务(带有sql server后端)来管理用户和RavenDb用于其他所有事情。
我是单位测试的新手,如果我能用一个示例方法跑过你到目前为止的所有内容,我会很感激。
这是HelixManager
public class HelixManager:IDisposable
{
private readonly IMembershipProvider _membership;
private readonly IRepository _repos;
public HelixManager()
{
_membership = new AspNetMembershipProvider();
_repos = new RavenRepository();
}
public HelixManager(IMembershipProvider membershipProvider, IRepository repos)
{
_membership = membershipProvider;
_repos = repos;
}
public User CreateAdmin(User newUser, string password)
{
if (String.IsNullOrEmpty(newUser.Email)) throw new ArgumentException("Email must be supplied");
if (String.IsNullOrEmpty(password)) throw new ArgumentException("Password must be supplied");
var memberId = _membership.CreateUser(newUser, password);
if (memberId != null)
{
_membership.AddToRole(newUser, "Admin");
newUser.Type = UserType.Admin;
newUser.MemberId = memberId;
_repos.Store<User>(newUser);
}
return newUser;
}
这是IMembershipProvider
public interface IMembershipProvider
{
string CreateUser(User newUser, string password);
void AddToRole(User user, string rolename);
}
和实施AspNetMembershipProvider
public class AspNetMembershipProvider : IMembershipProvider
{
public string CreateUser(User newUser, string password)
{
MembershipCreateStatus status;
MembershipUser memUser = System.Web.Security.Membership.CreateUser(newUser.Email, password, newUser.Email, "", "", true, out status);
return memUser.ProviderUserKey.ToString();
}
public void AddToRole(User user, string role)
{
Roles.AddUserToRole(user.Email, role);
}
}
这是IRepository
public interface IRepository
{
T Store<T>(T item);
}
及其实施
public class RavenRepository : IRepository
{
private readonly DocumentStore _store;
public RavenRepository()
{
_store = new DocumentStore { DefaultDatabase = "Helix", Url = "http://localhost:8080" };
_store.Initialize();
}
public T Store<T>(T item)
{
using (var session = _store.OpenSession())
{
session.Store(item);
session.SaveChanges();
}
return item;
}
}
在我的测试项目中,我创建了两个虚假实现:
FakeMembershipProvider:
class FakeMembershipProvider : IMembershipProvider
{
public string CreateUser(User newUser, string password)
{
CreatedUser = true;
return newUser.Email == "email@example.com" ? Guid.NewGuid().ToString() : null;
}
public void AddToRole(User user, string rolename)
{
AddedToRole = true;
}
public bool AddedToRole;
public bool CreatedUser;
}
和FakeRepository:
public class FakeRepository : IRepository
{
public T Store<T>(T item)
{
StoreCalled = true;
return item;
}
public bool StoreCalled;
}
测试大致如下:
public class UserManagementTests
{
private readonly HelixManager _hm;
private readonly IMembershipProvider _fakeMembershipProvider;
private readonly IRepository _fakeRepository;
public UserManagementTests()
{
_fakeMembershipProvider = new FakeMembershipProvider();
_fakeRepository = new FakeRepository();
_hm = new HelixManager(_fakeMembershipProvider, _fakeRepository);
}
[TestMethod]
public void CreateAdminReturnsValidAdminUser()
{
var newUser = new User
{
AvatarName = "fred",
Email = "email@example.com",
Forename = "Fred",
Surname = "Jones"
};
_hm.CreateAdmin(newUser, "password");
Assert.IsNotNull(newUser.MemberId);
Assert.AreEqual(UserType.Admin, newUser.Type);
}
在我进一步了解这条线之前,我要问的是,这是正确的方法吗?或者有更好的方法吗?
我还计划有一个IntegrationTests项目,该项目将使用真正的数据库和真实的RavenDb实例进行端到端测试。
干杯,
戴夫
答案 0 :(得分:2)
你的测试对我来说绝对没问题。正确的方式(模拟)正确的方式(AAA)。
继续:)
答案 1 :(得分:2)
我认为这种做法没有错。您可以使用模拟工具(Rhino Mocks,Moq,NSubstitute)创建假货,而不是手工制作,但这实际上是个人偏好和个人使用工具的舒适度。
你的测试结构清晰,基于状态断言(这是一件好事),你不要试图同时测试太多东西,这是一个常见的错误(即使对于我们这些人来说也是如此)一会儿)。
如果你还没有看到它,我强烈推荐Roy Osherove's Art of Unit Testing,它有很多关于单元测试的非常好的信息,包括保持测试清洁,如何处理不太可测试的代码区域等。
我说保持卡车':)
答案 2 :(得分:2)
我的问题实际上就是这个:
我正在启动一个Web应用程序 使用asp.net会员服务 (用sql server后端)来查看 用户和RavenDb之后的一切 其他
你为什么要这样做? 在RavenDB中创建所有内容会更容易,并且您的单元测试问题就像新的EmbeddableDocumentStore {RunInMemory = true}
一样简单