使用基础 class 进行集成测试
Using a base class for an integration test
我的基础 class 集成测试:
[TestClass]
public class BaseIntegrationTest
{
protected readonly ApplicationDbContext _dbContext;
public BaseIntegrationTest()
{
_dbContext = new ApplicationDbContext("DefaultConnectionTest");
}
[ClassInitialize]
public void Initialize()
{
InsertTestData();
}
public void InsertTestData()
{
_dbContext.Users.Add(new User { Name = "John Doe" });
}
}
这是一个继承自 BaseIntegrationTest
的测试 class:
[TestClass]
public class UserRepositoryTests : BaseIntegrationTest
{
// how to lose this method here and use the one in the BaseIntegrationTest?
//[ClassInitialize]
//public static void Setup(TestContext context)
//{
// BaseIntegrationTest test = new BaseIntegrationTest();
// test.InsertTestData();
//}
[TestMethod]
public void GetUser()
{
Filter f = new Filter()
{
Name = "John Doe"
};
UserRepository fr = new UserRepository(_dbContext);
var result = fr.GetUser(f);
Assert.IsTrue(result.Any(x => x.Name == "John Doe"));
}
}
BaseIntegrationTest
中用 [ClassInitialize]
属性修饰的方法永远不会执行,因此,我的测试失败了。没有数据被插入到数据库中。
但是如果我取消注释 UserRepositoryTests
中的 public static void Setup(TestContext context)
它会起作用。
我还有几个要测试的存储库。我希望将数据插入到数据库中并在基础 class 中完成,这样我就可以 运行 所有测试,而无需为我要测试的每个存储库重新创建数据库。
将public void Initialize()
转换为public static void Initialize(TestContext context)
也不起作用。 Initialize()
不会得到 executed/called。
我错过了什么吗?还是单元 test/integration 测试的这些限制?我对单元 testing/integration 测试还很陌生。
来自 MSDN:
Will the same approach that was used for [TestInitialize]
work with
[ClassInitialize]
in a base class?
Not exactly, if you create a [ClassInitialize]
attributed method in
the base class it won’t ever get called unless you explicitly call it
at the beginning of your derived test classes ClassInitialize
method; which of course is nowhere near as nice as the above approach.
http://blogs.msdn.com/b/densto/archive/2008/05/16/using-a-base-class-for-your-unit-test-classes.aspx
稍后介绍如何在继承任何方法之前进行初始化class:
How can I create an initialization method that will run before any
class initialization methods in my test project?
Building on the common base class approach described above you could
simply add a static constructor to your base class and either perform
the initialization there or call the method that will perform the
desired initialization. The resulting base class might look like
this:
[TestClass]
public class TestBase
{
static TestBase()
{
s_log = new StringBuilder();
Log.AppendLine("TestBase.ctor()");
}
[TestInitialize]
public void BaseTestInit()
{
Log.AppendLine("TestBase.BaseTestInit()");
}
[TestCleanup]
public void BaseTestCleanup()
{
Console.WriteLine(Log.ToString());
}
public static StringBuilder Log
{
get { return s_log; }
}
static StringBuilder s_log;
}
虽然此模式适用于 nunit,但似乎不适用于 mstest,因为无法继承 ClassInitializeAttribute。
一种变通方法是在基础的构造函数中进行初始化 class。
类似于:
[TestClass]
public class BaseIntegrationTest
{
protected readonly ApplicationDbContext _dbContext;
public BaseIntegrationTest()
{
_dbContext = new ApplicationDbContext("DefaultConnectionTest");
InsertTestData();
}
public void InsertTestData()
{
_dbContext.Users.Add(new User { Name = "John Doe" });
}
}
您可以添加一个静态标志来防止它 运行 每次测试:
[TestClass]
public class BaseIntegrationTest
{
private static bool _testsInitialized = false;
protected readonly ApplicationDbContext _dbContext;
public BaseIntegrationTest()
{
if(!_testsInitialized) {
_dbContext = new ApplicationDbContext("DefaultConnectionTest");
InsertTestData();
_testsInitialized = true;
}
}
public void InsertTestData()
{
_dbContext.Users.Add(new User { Name = "John Doe" });
}
}
..相当不优雅,但可能比将 ApplicationDbContext 设为静态(以及从静态 ctor 调用的所有其他方法)更优雅
我的基础 class 集成测试:
[TestClass]
public class BaseIntegrationTest
{
protected readonly ApplicationDbContext _dbContext;
public BaseIntegrationTest()
{
_dbContext = new ApplicationDbContext("DefaultConnectionTest");
}
[ClassInitialize]
public void Initialize()
{
InsertTestData();
}
public void InsertTestData()
{
_dbContext.Users.Add(new User { Name = "John Doe" });
}
}
这是一个继承自 BaseIntegrationTest
的测试 class:
[TestClass]
public class UserRepositoryTests : BaseIntegrationTest
{
// how to lose this method here and use the one in the BaseIntegrationTest?
//[ClassInitialize]
//public static void Setup(TestContext context)
//{
// BaseIntegrationTest test = new BaseIntegrationTest();
// test.InsertTestData();
//}
[TestMethod]
public void GetUser()
{
Filter f = new Filter()
{
Name = "John Doe"
};
UserRepository fr = new UserRepository(_dbContext);
var result = fr.GetUser(f);
Assert.IsTrue(result.Any(x => x.Name == "John Doe"));
}
}
BaseIntegrationTest
中用 [ClassInitialize]
属性修饰的方法永远不会执行,因此,我的测试失败了。没有数据被插入到数据库中。
但是如果我取消注释 UserRepositoryTests
中的 public static void Setup(TestContext context)
它会起作用。
我还有几个要测试的存储库。我希望将数据插入到数据库中并在基础 class 中完成,这样我就可以 运行 所有测试,而无需为我要测试的每个存储库重新创建数据库。
将public void Initialize()
转换为public static void Initialize(TestContext context)
也不起作用。 Initialize()
不会得到 executed/called。
我错过了什么吗?还是单元 test/integration 测试的这些限制?我对单元 testing/integration 测试还很陌生。
来自 MSDN:
Will the same approach that was used for
[TestInitialize]
work with[ClassInitialize]
in a base class?Not exactly, if you create a
[ClassInitialize]
attributed method in the base class it won’t ever get called unless you explicitly call it at the beginning of your derived test classesClassInitialize
method; which of course is nowhere near as nice as the above approach.
http://blogs.msdn.com/b/densto/archive/2008/05/16/using-a-base-class-for-your-unit-test-classes.aspx
稍后介绍如何在继承任何方法之前进行初始化class:
How can I create an initialization method that will run before any class initialization methods in my test project?
Building on the common base class approach described above you could simply add a static constructor to your base class and either perform the initialization there or call the method that will perform the desired initialization. The resulting base class might look like this:
[TestClass]
public class TestBase
{
static TestBase()
{
s_log = new StringBuilder();
Log.AppendLine("TestBase.ctor()");
}
[TestInitialize]
public void BaseTestInit()
{
Log.AppendLine("TestBase.BaseTestInit()");
}
[TestCleanup]
public void BaseTestCleanup()
{
Console.WriteLine(Log.ToString());
}
public static StringBuilder Log
{
get { return s_log; }
}
static StringBuilder s_log;
}
虽然此模式适用于 nunit,但似乎不适用于 mstest,因为无法继承 ClassInitializeAttribute。
一种变通方法是在基础的构造函数中进行初始化 class。
类似于:
[TestClass]
public class BaseIntegrationTest
{
protected readonly ApplicationDbContext _dbContext;
public BaseIntegrationTest()
{
_dbContext = new ApplicationDbContext("DefaultConnectionTest");
InsertTestData();
}
public void InsertTestData()
{
_dbContext.Users.Add(new User { Name = "John Doe" });
}
}
您可以添加一个静态标志来防止它 运行 每次测试:
[TestClass]
public class BaseIntegrationTest
{
private static bool _testsInitialized = false;
protected readonly ApplicationDbContext _dbContext;
public BaseIntegrationTest()
{
if(!_testsInitialized) {
_dbContext = new ApplicationDbContext("DefaultConnectionTest");
InsertTestData();
_testsInitialized = true;
}
}
public void InsertTestData()
{
_dbContext.Users.Add(new User { Name = "John Doe" });
}
}
..相当不优雅,但可能比将 ApplicationDbContext 设为静态(以及从静态 ctor 调用的所有其他方法)更优雅