Saat ini metode yang diuji terlalu erat dengan masalah implementasi untuk membuatnya mudah diuji unit secara terpisah. Coba singkirkan masalah implementasi tersebut sehingga dapat diejek dengan mudah untuk pengujian yang terisolasi.
public interface IDbConnectionFactory {
IDbConnection CreateConnection();
}
Abstraksi pabrik koneksi di atas dapat digunakan untuk mengakses System.Data
lain yang diperlukan abstraksi penyimpanan data MySql Anda.
public class MyDataAccessClass {
private IDbConnectionFactory connectionFactory;
public MyDataAccessClass(IDbConnectionFactory connectionFactory) {
this.connectionFactory = connectionFactory;
}
public void Insert(string firstname, string lastname) {
var query = $"INSERT INTO `sakila`.`actor`(`first_name`,`last_name`) VALUES('" + firstname + "','" + lastname + "')";
Console.WriteLine(query);
using(var connection = connectionFactory.CreateConnection() {
//Creates and returns a MySqlCommand object associated with the MySqlConnection.
using(var command = connection.CreateCommand()) {
command.CommandText = query;
Console.WriteLine("Established connection");
connection.Open();
command.ExecuteNonQuery();
Console.WriteLine("Insert query succesfully executed.");
connection.Close();//is not actually necessary as the using statement will make sure to close the connection.
}
}
}
}
Implementasi produksi pabrik akan mengembalikan MySqlConnection
yang sebenarnya
public class MySqlConnectionFactory: IDbConnectionFactory {
public IDbConnection CreateConnection() {
return new MySqlConnection("connection string");
}
}
yang dapat diteruskan ke lapisan data melalui injeksi ketergantungan
Untuk pengujian, Anda mengolok-olok antarmuka menggunakan kerangka kerja pilihan Anda atau membuat tiruan Anda sendiri untuk menyuntikkan dan menguji metode Anda.
[TestClass]
public class DataAccessLayerUnitTest {
[TestMethod]
public void TestInsert() {
//Arrange
var commandMock = new Mock<IDbCommand>();
commandMock
.Setup(m => m.ExecuteNonQuery())
.Verifiable();
var connectionMock = new Mock<IDbConnection>();
connectionMock
.Setup(m => m.CreateCommand())
.Returns(commandMock.Object);
var connectionFactoryMock = new Mock<IDbConnectionFactory>();
connectionFactoryMock
.Setup(m => m.CreateConnection())
.Returns(connectionMock.Object);
var sut = new MyDataAccessClass(connectionFactoryMock.Object);
var firstName = "John";
var lastName = "Doe";
//Act
sut.Insert(firstName, lastName);
//Assert
commandMock.Verify();
}
}
Terakhir, disarankan agar Anda menggunakan parameter perintah dalam teks perintah karena membangun string kueri secara manual membuka kode hingga serangan injeksi SQL.
Untuk lebih memahami cara menggunakan Moq, periksa Quickstart mereka