데이터베이스를 조롱했습니다. 테스트에서 데이터베이스를 다루는 것은 데이터베이스를 생성하고, 스키마를 생성 한 다음 드롭하고, 연결이 끊어지지 않았는지 확인하는 등의 과정을 거쳐야 고통을 받는다.
나를 괴롭히는 또 다른 사실은 코드 논리를 확인하는 것이 코드에서 "너무 멀리"있다는 사실입니다. mockable 클래스 뒤에 SQL 함수 (연결, 명령 등)를 넣고 DAL이 올바른 메서드를 호출하는지 확인합니다. 또한이 방법은 테스트를 훨씬 빠르게 수행합니다.
다음은 몇 가지 빠른 SQL 추상화 클래스 및 예제 사용 + 단위 테스트입니다.
public class SqlConnectionBase : IDisposable {
private readonly SqlConnection m_Connection;
public SqlConnectionBase(string connString) {
m_Connection = new SqlConnection(connString);
}
public virtual SqlConnection Object { get { return m_Connection; } }
public virtual void Open() {
m_Connection.Open();
}
public virtual void Close() {
m_Connection.Close();
}
#region IDisposable Members
public virtual void Dispose() {
m_Connection.Dispose();
}
#endregion
}
public class SqlCommandBase : IDisposable{
private readonly SqlCommand m_Command;
public SqlCommandBase() {
m_Command = new SqlCommand();
}
public SqlCommandBase(string cmdText, SqlConnectionBase connection) {
m_Command = new SqlCommand(cmdText, connection.Object);
}
public SqlCommandBase(SqlConnectionBase connection) {
m_Command = new SqlCommand();
m_Command.Connection = connection.Object;
}
public virtual int ExecuteNonQuery() { return m_Command.ExecuteNonQuery(); }
public virtual string CommandText { get { return m_Command.CommandText; } set { m_Command.CommandText = value; } }
public virtual void AddParameter(SqlParameter sqlParameter) {
m_Command.Parameters.Add(sqlParameter);
}
#region IDisposable Members
virtual public void Dispose() {
m_Command.Dispose();
}
#endregion
}
public class SqlFactory {
public virtual SqlCommandBase CreateCommand(string query, SqlConnectionBase conn) {
return new SqlCommandBase(query, conn);
}
public virtual SqlCommandBase CreateCommand(SqlConnectionBase conn) {
return new SqlCommandBase(conn);
}
public virtual SqlConnectionBase CreateConnection(string connString) {
return new SqlConnectionBase(connString);
}
}
public class DBUser {
public DBUser(SqlFactory factory) {
m_factory = factory; //dependency constructor, will be used during unit testing
}
public DBUser() {
m_factory = new SqlFactory(); //used during normal execution
}
public void DoSomething() {
var conn = m_factory.CreateConnection("server=servername,database=...");
var cmd = m_factory.CreateCommand(conn);
cmd.CommandText = "Select * from users";
cmd.ExecuteNonQuery();
}
[TestMethod]
public void DoSomethingTest() {
var factoryMock = new Mock<SqlFactory>();
var cmdMock = new Mock<CommandBase>();
factoryMock.Setup(f=>f.CreateConnection(It.IsAny<string>())).Returns(cmdMock.Object);
DBUser dbUser = new DBUser(factoryMock.Object);
dbUser.DoSomething();
//Verify that DoSomething is called.
cmdMock.Verify(c=>c.DoSomething());
}
}
테스트가 훨씬 빠르게 실행됩니다. 상상할 수 있습니다. 설명 한 내용의 샘플 코드가 있습니까? – XIII
나는 조각이 있는데, [System.IO.Abstractions] (http://systemioabstractions.codeplex.com/)와 비슷한'System.Sql.Abstractions' 라이브러리 작성을 진지하게 고려하고 있습니다. –