I øjeblikket er den metode, der testes, for tæt koblet til implementeringsproblemer til at gøre den let enhedstestbar i isolation. Prøv at abstrahere disse implementeringsproblemer, så de let kan hånes for isolerede tests.
public interface IDbConnectionFactory {
IDbConnection CreateConnection();
}
Ovenstående forbindelsesfabriksabstraktion kan bruges til at få adgang til de andre nødvendige System.Data
abstraktioner af dit MySql-datalager.
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.
}
}
}
}
Produktionsimplementeringen af fabrikken vil returnere en faktisk MySqlConnection
public class MySqlConnectionFactory: IDbConnectionFactory {
public IDbConnection CreateConnection() {
return new MySqlConnection("connection string");
}
}
som kan overføres til datalaget via afhængighedsinjektion
For at teste håner du grænsefladerne ved at bruge din valgte hånende ramme eller laver dine egne forfalskninger for at injicere og teste din metode.
[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();
}
}
Endelig er det tilrådeligt, at du bruger kommandoparametre i kommandoteksten, da konstruktion af forespørgselsstrengen manuelt åbner koden op til SQL-injektionsangreb.
For bedre at forstå, hvordan man bruger Moq, tjek deres Quickstart