单元测试Raven和ASP.NET成员资格

时间:2011-07-07 16:41:09

标签: asp.net unit-testing ravendb

我正在启动一个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实例进行端到端测试。

干杯,

戴夫

3 个答案:

答案 0 :(得分:2)

你的测试对我来说绝对没问题。正确的方式(模拟)正确的方式(AAA)。

继续:)

答案 1 :(得分:2)

我认为这种做法没有错。您可以使用模拟工具(Rhino MocksMoqNSubstitute)创建假货,而不是手工制作,但这实际上是个人偏好和个人使用工具的舒适度。

你的测试结构清晰,基于状态断言(这是一件好事),你不要试图同时测试太多东西,这是一个常见的错误(即使对于我们这些人来说也是如此)一会儿)。

如果你还没有看到它,我强烈推荐Roy Osherove's Art of Unit Testing,它有很多关于单元测试的非常好的信息,包括保持测试清洁,如何处理不太可测试的代码区域等。

我说保持卡车':)

答案 2 :(得分:2)

我的问题实际上就是这个:

  

我正在启动一个Web应用程序   使用asp.net会员服务   (用sql server后端)来查看   用户和RavenDb之后的一切   其他

你为什么要这样做? 在RavenDB中创建所有内容会更容易,并且您的单元测试问题就像新的EmbeddableDocumentStore {RunInMemory = true}

一样简单