Как к модульному тесту членство Asp.net?

Это означает «короткое замыкание или» . То есть если первая часть выражения ложна, используйте вторую. В Википедии есть статья об этом с синтаксисом для ряда языков.

15
задан Dave New 5 May 2015 в 14:56
поделиться

3 ответа

Вы можете протестировать свои контроллеры и большую часть своего настраиваемого поставщика, преобразовав свой собственный код членства в два уровня: репозиторий доступа к данным, который взаимодействует только с базой данных, и уровень обслуживания, который использует репозиторий компоненты для предоставления API членства. Уровень сервиса - это то место, где вы должны проверять аргументы, удерживать и применять параметры, такие как EnablePasswordReset, и переводить любые исключения базы данных или коды состояния в форму, подходящую для использования контроллером.

Когда вы указываете каждый уровень с его собственным интерфейсом, потребители могут писать в него интерфейс независимо от того, как он реализован. Когда ваше приложение работает, ваш провайдер, конечно, обращается к базе данных через эти интерфейсы, но для тестирования вы можете имитировать репозиторий или интерфейсы служб. Вы можете протестировать свой уровень сервиса, издевательски над уровнем репозитория, без необходимости возиться с базой данных или файлом web.config, и вы можете протестировать свои контроллеры, высмеивая уровень сервиса. Если вы не хотите проводить рефакторинг всего провайдера, вы все равно можете протестировать свои контроллеры, если только создадите интерфейс службы и заставите свои контроллеры использовать его.

Чтобы быть конкретным, если немного многословно, ваш репозиторий и интерфейсы служб могут выглядит примерно так:

namespace Domain.Abstract {
    public interface IRepository {
        string ConnectionString { get; }
    }
}

namespace Domain.Abstract {
    public interface IUserRepository : IRepository {
        MembershipUser CreateUser(Guid userId, string userName, string password, PasswordFormat passwordFormat, string passwordSalt,
                string email, string passwordQuestion, string passwordAnswer, bool isApproved,
                DateTime currentTimeUtc, bool uniqueEmail);
        MembershipUser GetUser(Guid userId, bool updateLastActivity, DateTime currentTimeUtc);
        PasswordData GetPasswordData(Guid userId, bool updateLastLoginActivity, DateTime currentTimeUtc);
        void UpdatePasswordStatus(Guid userId, bool isAuthenticated, int maxInvalidPasswordAttempts, int passwordAttemptWindow, 
                      DateTime currentTimeUtc, bool updateLastLoginActivity, DateTime lastLoginDate, DateTime lastActivityDate);
        //....
    }
}

namespace Domain.Abstract {
  public interface IUserService {
    bool EnablePasswordRetrieval { get; }
    bool EnablePasswordReset { get; }
    bool RequiresQuestionAndAnswer { get; }
    bool RequiresUniqueEmail { get; }
    //....

    MembershipUser CreateUser(string applicationName, string userName, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved);
    MembershipUser GetUser(Guid userId, bool userIsOnline);
    bool ValidateUser(Guid userId, string password);
    //...
    }
}

namespace Domain.Concrete {
  public class UserService : IUserService {
    private IUserRepository _userRepository;


    public UserService(IUserRepository userRepository) {
        _userRepository = userRepository;
    }
    //...
    public bool ValidateUser(Guid userId, string password) {
        // validate applicationName and password here
        bool ret = false;
        try {
            PasswordData passwordData;
            ret = CheckPassword(userId, true, true, DateTime.UtcNow, out passwordData);
        }
        catch (ObjectLockedException e) {
            throw new RulesException("userName", Resource.User_AccountLockOut);
        }
        return ret;
    }

    private bool CheckPassword(Guid userId, string password, bool updateLastLoginActivityDate, bool failIfNotApproved,
                                DateTime currentTimeUtc, out PasswordData passwordData) {
        passwordData = _userRepository.GetPasswordData(userId, updateLastLoginActivityDate, currentTimeUtc);

        if (!passwordData.IsApproved && failIfNotApproved)
            return false;

        string encodedPassword = EncodePassword(password, passwordData.PasswordFormat, passwordData.PasswordSalt);
        bool isAuthenticated = passwordData.Password.Equals(encodedPassword);

        if (isAuthenticated && passwordData.FailedPasswordAttemptCount == 0 && passwordData.FailedPasswordAnswerAttemptCount == 0)
            return true;
        _userRepository.UpdatePasswordStatus(userId, isAuthenticated, _maxInvalidPasswordAttempts, _passwordAttemptWindow,
                                            currentTimeUtc, updateLastLoginActivityDate,
                                            isAuthenticated ? currentTimeUtc : passwordData.LastLoginDate,
                                            isAuthenticated ? currentTimeUtc : passwordData.LastActivityDate);

        return isAuthenticated;
    }
}
7
ответ дан 1 December 2019 в 04:53
поделиться

Система членства Asp.Net разработана для работы в контексте запроса Asp.Net. Итак, у вас есть три варианта.

  1. Большинство людей, столкнувшись с такой зависимостью, напишут вокруг нее тонкую оболочку. Обертка ничего не делает, просто перенаправляет все вызовы базовой зависимости. Так что они просто не проверяют это. Ваш AuthenticateUser является такой оболочкой. Вероятно, вам следует сделать все методы виртуальными или извлечь интерфейс, чтобы сделать его подделываемым, но это уже другая история.
  2. Используйте TypeMock Isolator и имитируйте членство.
  3. Используйте инфраструктуру Ivonna и запустите свой тест в контексте Asp.Net (это будет тест интеграции).
3
ответ дан 1 December 2019 в 04:53
поделиться

К сожалению, вы не можете просто скопировать файл web.config или app.config и заставить его работать таким образом. Причина в том, что ваша сборка выполняется внутри процесса NUnit, а не под вашим приложением.

Чтобы исправить ситуацию, вам, вероятно, придется издеваться или заглушать членов членства, которым вы звоните, или следовать Соглашению over Подход к настройке параметров, которые вы сохранили в своем файле web.config.

Существует много фреймворков для фиксации, но вот пара: Rhino Mocks , Moq

Также, чтобы следовать подходу «Соглашение вместо конфигурации», вы можете сделать что-то вроде этого:

static ConfigurationSettings
{
     static String SomeSetting
     {
        get
        {
           var result = "HARDCODEDVALUE";
           if (ConfigurationManager.AppSettings["SOMEKEY"] != null)
               result = ConfigurationManager.AppSettings["SOMEKEY"];
           return result;
     }
}

Затем вы можете использовать этот код следующим образом:

//this is how the old code might look
var mySetting = ConfigurationManager.AppSettings["SOMEKEY"];
//use the setting

//this is how the new code would look
var mySetting = ConfigurationSettings.SomeSetting;
//use the setting   

Таким образом, ваш тест будет работать, и когда вы запустите его в своем приложении, он будет использовать любую конфигурацию настройки, которые вы сохранили.

1
ответ дан 1 December 2019 в 04:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: