我在测试中配置了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
从哪里获取容器?
我的Windsor适配器永远不会被要求Resolve
存储库的组件。
如何给容器AppHostHttpListenerBase
以便它可以解决这些依赖?或者我需要以另一种方式配置它吗?
答案 0 :(得分:1)
尝试在TestAppHostHttpListenerBase.Configure
方法的顶部设置容器适配器,而不是在BaseTest
类中设置:
public override void Configure(Container container)
{
container.Adapter = new WindsorContainerAdapter();
...
}
Container
方法的TestAppHostHttpListenerBase.Configure
对象是在TestAppHostHttpListenerBase的基础构造函数中创建的;你没有直接控制它的创建。这是您需要使用适配器等自定义的容器实例
如果您还需要在UserProfileBehaviours
或其他单元测试类中使用相同的IoC容器,我认为您可以通过静态EndpointHost.Container
属性引用它,并消除正在进行的额外容器实例在BaseTest
构造函数中创建。如上所述,在OnTestFixtureSetUp
中实例化AppHost对象后,容器对象将变为可用。