Как выполнить модульное тестирование репозитория и макетировать базу данных с помощью moq - PullRequest
0 голосов
/ 28 апреля 2020

Я вхожу в одиночку в существующем проекте, в котором нет ни одного модульного теста. Моя первая цель перед рефакторингом - покрыть 100% кода. Я хотел бы избежать какой-либо регрессии.

Я прочитал Как мне смоделировать sqlconnection или я должен рефакторинг кода? но мой случай, как вы можете видеть ниже, совершенно другой, потому что мне нужно сделать больше, чем заглушка просто sqlConnection. В основном мне нужно издеваться над БД. Я хотел бы знать лучший подход для достижения этого.

(Кстати, я не хочу использовать какой-либо ORM, такой как Entity). Ниже код репозитория:

public class HotelRepository : IHotelRepository
{
    private readonly IDbConnection _dbConnection;
    private readonly ILogService _loggerService;

    public HotelRepository(IDbConnection dbConnection, ILogService loggerService)
    {
        _dbConnection = dbConnection;
        _loggerService = loggerService;
    }

    public HotelDo GetByRid(string rid)
    {
        return Find(rid).FirstOrDefault();
    }

    public List<HotelDo> Find(string text)
    {
        try
        {
            _dbConnection.Open();

            var items = new List<HotelDo>();
            using (var command = _dbConnection.CreateCommand())
            {
                command.CommandType = CommandType.StoredProcedure;
                command.CommandText = "dbo.HotelSearchByRidOrName";

                command.Parameters.Add(new SqlParameter("@Text", text));

                using (var reader = command.ExecuteReader(CommandBehavior.CloseConnection))
                {
                    while (reader.Read())
                    {
                        items.Add(new HotelDo()
                        {
                            Name = SqlExtension.ReaderToStringConverter(reader["Name"]),
                            Id = SqlExtension.ReaderToIntConverter(reader["Id"]),
                            Rid = SqlExtension.ReaderToStringConverter(reader["RIDHotel"]),
                            IdPms = SqlExtension.ReaderToNullableIntConverter(reader["IdPms"]),
                            LinkResaWeb = SqlExtension.ReaderToStringConverter(reader["LinkResaWeb"]),
                            LinkPms = SqlExtension.ReaderToStringConverter(reader["LinkPms"]),
                            IdBrand = SqlExtension.ReaderToNullableIntConverter(reader["IdBrand"]) ?? 0,
                            IsOnline = SqlExtension.ReaderToBoolConverter(reader["IsOnline"]) ?? false,
                            CodeCountry = SqlExtension.ReaderToStringConverter(reader["CodeCountry"])
                        });
                    }
                }
            }
            return items;
        }
        catch (Exception e)
        {
            var errorMessage = $"HotelRepository Find, text {text} ";
            _loggerService.Trace(LogSeverity.Error, errorMessage, e);

            throw new DalException() { Source = errorMessage, };
        }
        finally
        {
            _dbConnection.Close();
        }
    }

    public List<HotelDo> GetAll()
    {
        try
        {
            _dbConnection.Open();

            var items = new List<HotelDo>();
            using (var command = _dbConnection.CreateCommand())
            {
                command.CommandType = CommandType.StoredProcedure;
                command.CommandText = "dbo.HotelGetAll";

                using (var reader = command.ExecuteReader(CommandBehavior.CloseConnection))
                {
                    while (reader.Read())
                    {
                        bool.TryParse(reader["IsOnline"].ToString(), out var isOnline);

                        items.Add(new HotelDo()
                        {
                            Id = SqlExtension.ReaderToIntConverter(reader["Id"]),
                            Rid = SqlExtension.ReaderToStringConverter(reader["RIDHotel"]),
                            Name = SqlExtension.ReaderToStringConverter(reader["Name"]),
                            CodeCountry = SqlExtension.ReaderToStringConverter(reader["CodeCountry"]),
                            LinkPms = SqlExtension.ReaderToStringConverter(reader["LinkPms"]),
                            IdPms = SqlExtension.ReaderToNullableIntConverter(reader["IdPms"]),
                            IdBrand = SqlExtension.ReaderToNullableIntConverter(reader["IdBrand"]) ?? 0,
                            LinkResaWeb = SqlExtension.ReaderToStringConverter(reader["LinkResaWeb"]),
                            IsOnline = isOnline
                        });
                    }
                }
            }
            return items;
        }
        catch (Exception e)
        {
            var errorMessage = $"HotelRepository GetAllHotels";
            _loggerService.Trace(LogSeverity.Error, errorMessage, e);

            throw new DalException() { Source = errorMessage, };
        }
        finally
        {
            _dbConnection.Close();
        }
    }
}

Спасибо за помощь

1 Ответ

0 голосов
/ 28 апреля 2020

Итак, исходя из того, что у вас есть, я создал тестовый фрейм для вас. Для краткости я удалил менее важные компоненты.

Перед тем, как ты прыгнешь, я просто хочу дать свои 2 цента, если ты не знаешь, как делать такие вещи, ты, кажется, более или менее. в младшей должности или с меньшим опытом работы с C#, а также оказался в более или менее зрелой компании, которая не заботится об отставании в развитии, так как непокрытый проект просто брошен, говорит, что у вас нет много Ресурсы для go собираются улучшить базу кода.

  1. Проверяйте только те вещи, которые имеют деловую ценность (можете ли вы поставить цену за кусок логики c, если он тормозит)
  2. Быстрая доставка материала сделает вас лучше программист (никому в бизнесе наплевать на тестовую смекалку)
  3. Учиться усердно, набраться опыта, хорошей репутации и не бояться вырваться отсюда, как только вам надоест.

Main

void Main()
{
    var idIndex = 0;
    var ids = new string[] { "1", "2" };

    var mockDataReader = new Mock<IDataReader>();
    mockDataReader.SetupSequence(x => x.Read()).Returns(true).Returns(true).Returns(false);
    mockDataReader.SetupGet(x => x["Id"]).Returns(() => ids[idIndex]).Callback(() => idIndex++);

    var mockParameters = new Mock<IDataParameterCollection>();

    var mockCommand = new Mock<IDbCommand>();
    mockCommand.SetupGet(x => x.Parameters).Returns(mockParameters.Object);
    mockCommand.Setup(x => x.ExecuteReader(CommandBehavior.CloseConnection)).Returns(mockDataReader.Object);

    var mockConnection = new Mock<IDbConnection>();
    mockConnection.Setup(x => x.CreateCommand()).Returns(mockCommand.Object);

    var repo = new HotelRepository(mockConnection.Object);

    var result = repo.Find("search");

    Assert.Equal("1", result[0].Id);
    Assert.Equal("2", result[1].Id);
}

Хранилище

public class HotelRepository
{
    private readonly IDbConnection _dbConnection;

    public HotelRepository(IDbConnection dbConnection)
    {
        _dbConnection = dbConnection;
    }

    public List<Pony> Find(string text)
    {
        _dbConnection.Open();

        var items = new List<Pony>();
        using (var command = _dbConnection.CreateCommand())
        {
            command.CommandType = CommandType.StoredProcedure;
            command.CommandText = "dbo.HotelSearchByRidOrName";

            command.Parameters.Add(new SqlParameter("@Text", text));

            using (var reader = command.ExecuteReader(CommandBehavior.CloseConnection))
            {
                while (reader.Read())
                {
                    items.Add(new Pony
                    {
                        Id = reader["Id"].ToString()
                    });
                }
            }
        }
        return items;
    }
}

Просто тупой пони

public class Pony {
    public string Id { get; set; }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...