1

次のようにテストを実行する目的で、テストで ServiceStack AppHostHttpListenerBase を構成しました。

public class UserProfileBehaviours : BaseTest<UserProfileService>
{
    [Test]
    public void Can_access_secure_service()
    {
        var client = GetClientWithUserPassword();

        var result = ((IRestClient)client).Get(new Dto.View.Requests.UserProfileRequest
             {
                 Slug = "user"
             });

        result.Result.UserAccount.Username.Should().Be("user");
    }
}

私の BaseTest は次のようになります。

[TestFixture]
public class BaseTest<T>
{
    protected TestAppHostHttpListenerBase<T> AppHost;
    private const string ListeningOn = "http://localhost:82/";
    private const string UserName = "user";
    private const string Password = "p@55word";
    protected readonly Container Container;

    public BaseTest()
    {
        Container = new Funq.Container
        {
            Adapter = new WindsorContainerAdapter()
        };
    }

    [TestFixtureSetUp]
    public void OnTestFixtureSetUp()
    {
        AppHost = new TestAppHostHttpListenerBase<T>();

        AppHost.Init();

        AppHost.Start(ListeningOn);
    }

    [TestFixtureTearDown]
    public void OnTestFixtureTearDown()
    {
        AppHost.Dispose();
    }

    protected IServiceClient GetClient()
    {
        return new JsonServiceClient(ListeningOn);
    }

    protected IServiceClient GetClientWithUserPassword()
    {
        return new JsonServiceClient(ListeningOn)
        {
            UserName = UserName,
            Password = Password
        };
    }
}

そして、私の WindsorContainerAdapter:

public static class CastleWindsor
{
    public static IWindsorContainer InstallFromAssemblies(this IWindsorContainer container, params string[] assemblyNames)
    {
        return container.Install(assemblyNames.Select(
            x => (IWindsorInstaller)new AssemblyInstaller(Assembly.Load(x), new InstallerFactory())).ToArray());
    }
}


public class WindsorContainerAdapter : IContainerAdapter, IDisposable
{
    private readonly IWindsorContainer _container;

    public WindsorContainerAdapter()
    {
        _container = new WindsorContainer("Windsor.config");
        _container.Register(Component.For<IWindsorContainer>().Instance(_container));
        _container.Install(FromAssembly.InThisApplication(), FromAssembly.InDirectory(new ApplicationAssemblyFilter())).InstallFromAssemblies("Web.Api");
        _container.Register(Classes.FromAssemblyNamed("Web.Api").BasedOn(typeof(IRepository<>)).LifestyleSingleton());
        _container.Register(Component.For<IEmailBuilder>().ImplementedBy<EmailBuilder>().LifeStyle.Singleton);
        _container.Register(Component.For<IEmailSender>().ImplementedBy<EmailSender>().LifeStyle.Singleton);
        _container.Register(Component.For<IEmailService>().ImplementedBy<EmailService>());
    }

    public T TryResolve<T>()
    {
        return !_container.Kernel.HasComponent(typeof(T)) ? default(T) :
            Resolve<T>();
    }

    public T Resolve<T>()
    {
        return _container.Resolve<T>();
    }

    public void Dispose()
    {
        _container.Dispose();
    }
}

そして最後に私の TestAppHostHttpListener

public class TestAppHostHttpListenerBase<T> : AppHostHttpListenerBase
{
    public const string WebHostUrl = "http://localhost:82/";
    private InMemoryAuthRepository _userRep;
    private const string UserName = "user";
    private const string Password = "p@55word";
    public const string LoginUrl = "specialLoginPage.html";

    public TestAppHostHttpListenerBase()
        : base("Validation Tests", typeof(T).Assembly)
    {
    }

    public override void Configure(Container container)
    {

        var appSettings = new AppSettings();

        SetConfig(new EndpointHostConfig { WebHostUrl = WebHostUrl });

        Plugins.Add(new AuthFeature(
                        () =>
                        new AuthUserSession(),
                        new IAuthProvider[]
                            {
                                new BasicAuthProvider(),
                                new CredentialsAuthProvider(),
                                new TwitterAuthProvider(appSettings),
                                new FacebookAuthProvider(appSettings)
                            }, "~/" + LoginUrl));

        container.Register<ICacheClient>(new MemoryCacheClient());
        _userRep = new InMemoryAuthRepository();
        container.Register<IUserAuthRepository>(_userRep);
        CreateUser(1, UserName, null, Password, new List<string> { "TheRole" }, new List<string> { "ThePermission" });
    }

    private void CreateUser(int id, string username, string email, string password, List<string> roles = null, List<string> permissions = null)
    {
        string hash;
        string salt;
        new SaltedHash().GetHashAndSaltString(password, out hash, out salt);

        if (_userRep.GetUserAuthByUserName(username) == null)
        {
            _userRep.CreateUserAuth(new UserAuth
            {
                Id = id,
                DisplayName = "DisplayName",
                Email = email ?? "as@if{0}.com".Fmt(id),
                UserName = username,
                FirstName = "FirstName",
                LastName = "LastName",
                PasswordHash = hash,
                Salt = salt,
                Roles = roles,
                Permissions = permissions
            }, password);
        }
    }
}

コンテナーが構成されているときに、コンポーネントがあることがわかりますがUserAccountRepository、そのコンポーネントがUserProfileServiceクライアントの依存関係である場合、自動配線された依存関係を解決できなかったという例外を受け取ります。私が理解していないのは、どこAppHostHttpListenerBaseからコンテナを取得するのですか?

私のウィンザーアダプターはResolve、リポジトリのコンポーネントに要求されることはありません.

AppHostHttpListenerBaseこれらの依存関係を解決できるように、コンテナーにどのように与えることができますか? または、別の方法で構成する必要がありますか?

4

1 に答える 1

1

クラスTestAppHostHttpListenerBase.Configure内ではなく、メソッドの先頭にコンテナ アダプタを設定してみてください。BaseTest

public override void Configure(Container container)
{
    container.Adapter = new WindsorContainerAdapter();
    ...
}

メソッドに指定されたContainerオブジェクトTestAppHostHttpListenerBase.Configureは、TestAppHostHttpListenerBase の基本コンストラクターで作成されます。その作成を直接制御することはできません。これは、アダプターなどでカスタマイズする必要があるコンテナー インスタンスです。

UserProfileBehaviours自分または他の単体テスト クラスでも同じ IoC コンテナーを使用する必要がある場合は、静的プロパティを介して参照し、コンストラクターEndpointHost.Containerで作成されている余分なコンテナー インスタンスを削除できると思います。BaseTest上で暗示されているように、コンテナ オブジェクトは、AppHost オブジェクトを でインスタンス化した後に使用できるようになりますOnTestFixtureSetUp

于 2013-10-10T20:30:49.647 に答える