我想在我的数据库中运行一些存储过程的测试,而不会实际影响数据(或者更准确地说,在测试运行后没有持久的影响)。
经过一番研究后,我想出了在我的Visual Studio 2010测试项目中使用TransactionScope的方法,例如
using( new TransactionScope())
{
using( SqlConnection connection = new SqlConnection("someConnectionString"))
{
connection.Open();
using( SqlCommand command = new SqlCommand( "some sql", connection ))
{
// Do some database stuff...
}
}
}
现在这个工作正常,只要我把所有这些都放在一个测试方法中,即当TransactionScope的使用块完成时,我对数据库的所有更改都会自动回滚。
我现在的问题是我想在ClassInitialize中做一些数据库工作,所以我只需要为每个测试类做一次而不是每个测试方法。当我创建一个公共TransactionScope属性并在ClassInitialize方法中为它分配一个TransactionScope实例时,这没关系。一旦我在我的一个测试方法中执行任何与数据库相关的东西,我就会在该方法中遇到TransactionManagerCommunicationException。
我不太明白为什么会出现这种情况,我也想知道我的方法是否存在错误,或者如何在不设置TransactionScope(包括所有设置)的情况下使其工作再次在每种测试方法中进行测试的东西。
修改
下面的代码摘录,我希望这能提供足够的信息:
public TransactionScope Scope { get; set; }
[ClassInitialize]
public static void ClassInitialize( TestContext testContext )
{
Scope = new TransactionScope();
// Do some db set up stuff, e.g. create records used for tests etc.
}
[ClassCleanup]
public static void ClassCleanup()
{
Scope.Dispose();
}
[TestMethod]
public void MyTestMethod()
{
using( SqlConnection connection = new SqlConnection( "someConnectionString" ) )
{
DataTable result = new DataTable();
using( SqlCommand command = new SqlCommand( "spName", connection ) )
{
command.CommandType = CommandType.StoredProcedure;
using( SqlDataAdapter adapter = new SqlDataAdapter() )
{
adapter.SelecteCommand = command;
// The next line causes the exception to be thrown
adapter.Fill( result );
}
}
// Assertions against DataTable result
}
}
例外是
用户代码未处理TransactionManagerCommunicationException 已禁用分布式事务管理器(MSDTC)的网络访问。请使用组件服务管理工具在MSDTC的安全配置中启用DTC以进行网络访问。
我知道我可以尝试更改设置,但我不明白为什么我会先得到例外 - 与单个(测试)方法中的代码相比有什么不同?
提前致谢
最好的问候
-G。
答案 0 :(得分:4)
您的例外是说未启用MSDTC。我的猜测是,当你单独使用TransactionScope时,它只是创建本地SQL事务 - 不需要DTC。但是,当您通过多个连接共享TransactionScope时,事务将通过DTC“升级”为分布式事务,您可能尚未启用该事务。
尝试在本地计算机和服务器上启用MSDTC上的网络访问。这样做的步骤会有所不同,具体取决于您的操作系统。 Here's how to do it in Win 2003 Server。 Here's a link for Win 2008。请注意,您可能还需要通过防火墙启用DTC(在上一个链接中进行了解释......)
答案 1 :(得分:0)
你可以创建这样的设置:
void Main()
{
using(new SetupTransaction())
{
//Your test
}
}
public class SetupTransaction : IDisposable
{
private TransactionScope transaction;
public SetupTransaction()
{
transaction = new TransactionScope();
//Do your stuff here
}
public void Dispose()
{
transaction.Dispose();
}
}
至于你得到的错误,你能准确发布你的实施方式吗?
答案 2 :(得分:0)
我成功使用的一种方法是创建一个实现设置和拆卸的基类。在setup方法中,您将创建一个新的事务范围并将其存储在私有类变量中。在拆解方法中,您回滚事务范围。
我正在使用NUNit,但MSTest的原则应该相同。这里的线索是SetUp
和TearDown
在每个单元测试之前和之后执行一次,以确保单元测试之间的隔离。
此外,正如@blech所提到的,必须运行Microsoft分布式事务处理协调器(MSDTC)服务才能使此解决方案正常工作。