Metoden som testas för närvarande är för hårt kopplad till implementeringsproblem för att göra den enkelt enhetstestbar isolerad. Försök att ta bort dessa implementeringsproblem så att de lätt kan hånas för isolerade tester.
public interface IDbConnectionFactory {
IDbConnection CreateConnection();
}
Ovanstående anslutningsfabriksabstraktion kan användas för att komma åt andra nödvändiga System.Data
abstraktioner av ditt 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 av fabriken kommer att returnera en faktisk MySqlConnection
public class MySqlConnectionFactory: IDbConnectionFactory {
public IDbConnection CreateConnection() {
return new MySqlConnection("connection string");
}
}
som kan skickas in i datalagret via beroendeinjektion
För att testa hånar du gränssnitten med ditt val av hånande ramverk eller skapar dina egna förfalskningar för att injicera och testa din metod.
[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();
}
}
Slutligen är det tillrådligt att du använder kommandoparametrar i kommandotexten eftersom att konstruera frågesträngen manuellt öppnar koden för SQL-injektionsattacker.
För att bättre förstå hur du använder Moq, kolla deras snabbstart