我正在努力将 NHibernate 引入我们的代码库。我想我必须使用某种 DI 容器,这样我就可以将依赖项注入从数据库加载的实体中。我选择 Unity 作为容器。
我正在考虑使用 Unity 的拦截机制向我的代码添加事务方面,因此我可以执行以下操作:
class SomeService
{
[Transaction]
public void DoSomething(CustomerId id)
{
Customer c = CustomerRepository.LoadCustomer(id);
c.DoSomething();
}
}
处理[Transaction]
程序将负责创建会话和事务,提交事务(或回滚异常)等。
我担心使用这种拦截方式会束缚我在代码中几乎所有地方都使用 Unity。如果我以这种方式引入方面,那么我绝不能调用new SomeService()
,否则我将获得没有事务的服务。虽然这在生产代码中是可以接受的,但在测试中似乎开销太大。例如,我必须将其转换为:
void TestMethod()
{
MockDependency dependency = new MockDependency();
dependency.SetupForTest();
var service = SomeService(dependency);
service.DoSomething();
}
进入这个:
void TestMethod()
{
unityContainer.RegisterType<MockDependency>();
unityContainer.RegisterType<IDependency, MockDependency>();
MockDependency dependency = unityContainer.Resolve<MockDependency>();
dependency.SetupForTest();
var service = unityContainer.Resolve<SomeService>();
service.DoSomething();
}
这为我正在使用的每个模拟对象添加了 2 行代码,这导致了相当多的代码(我们的测试使用了很多有状态的模拟,因此测试类拥有 5-8 个模拟对象并不少见,并且有时更多。)
我不认为独立注入在这里会有所帮助:我必须为我在测试中使用的每个类设置注入,因为可以在编写测试后将方面添加到类中。
现在,如果我放弃使用拦截,我最终会得到:
class SomeService
{
public void DoSomething(CustomerId id)
{
Transaction.Run(
() => {
Customer c = CustomerRepository.LoadCustomer(id);
c.DoSomething();
});
}
}
诚然,这不是那么好,但似乎也没有那么糟糕。
我什至可以设置我自己的穷人的拦截:
class SomeService
{
[Transaction]
public void DoSomething(CustomerId id)
{
Interceptor.Intercept(
MethodInfo.GetCurrentMethod(),
() => {
Customer c = CustomerRepository.LoadCustomer(id);
c.DoSomething();
});
}
}
然后我的拦截器可以处理类的属性,但我仍然可以使用实例化类new
而不必担心失去功能。
有没有更好的使用 Unity 拦截的方法,它不会强迫我总是使用它来实例化我的对象?