Модульное тестирование Raven и ASP.NET Membership - PullRequest
4 голосов
/ 07 июля 2011

Я запускаю веб-приложение, которое будет использовать службы членства asp.net (с серверным сервером sql) для наблюдения за пользователями и 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, который будет использовать настоящий db и настоящий экземпляр RavenDb для сквозного тестирования.

Cheers,

Дэйв

Ответы [ 3 ]

2 голосов
/ 07 июля 2011

Я не вижу ничего плохого в этом подходе.Вы можете пойти по пути использования инструмента Mocking ( Rhino Mocks , Moq , NSubstitute ) для создания ваших подделок вместо того, чтобы делать это вручную, но этона самом деле это вопрос личных предпочтений и вашего личного уровня комфорта с помощью инструментов.

Ваш тест четко структурирован, он основан на состоянии (что хорошо), и вы не пытаетесь слишком много тестировать водин раз, что является распространенной ошибкой (даже для тех из нас, кто делал это некоторое время).

Если вы еще этого не видели, я настоятельно рекомендую Роя Ошерова Искусство юнит-тестирования , в котором есть много очень полезной информации о юнит-тестировании,включая такие вещи, как поддержание чистоты тестов, как работать с менее тестируемыми областями кода и т. д.

Я говорю: keep truckin ':)

2 голосов
/ 08 июля 2011

Моя проблема на самом деле с этим:

Я запускаю веб-приложение, которое будет использовать службы членства asp.net (с серверным сервером SQL), чтобы присматривать за пользователями и RavenDb для всегоеще.

Почему вы это делаете?Было бы проще сделать все в RavenDB, и проблема с модульным тестированием была бы такой же простой, как новый EmbeddableDocumentStore {RunInMemory = true}

2 голосов
/ 07 июля 2011

Ваши тесты выглядят абсолютно нормально для меня.Правильный подход (издевается) правильный путь (ААА).

Вперед:)

...