У меня есть этот юнит-тест. Он тестирует метод UpdateEmployee для моего IEmployeeService.
private readonly IEmployeeService _employeeService;
public EmployeeServiceTests()
{
var mockData = new List<Employee>
{
new Employee { Id = 0, FirstName = "Homer", LastName = "Simpson" },
new Employee { Id = 1, FirstName = "Carl", LastName = "Carlson" },
new Employee { Id = 2, FirstName = "Lenny", LastName = "Leonard" },
};
_employeeService = MockSetup.SetupEmployeeService(mockData);
}
[Fact]
public void UpdateEmployee_EmployeeExists_EmployeeGetsUpdated()
{
var homer = _employeeService.GetEmployee(0);
homer.FirstName = "Homer Jay";
_employeeService.UpdateEmployee(homer);
var actual = homer.FirstName;
var expected = _employeeService.GetEmployee(0).FirstName;
Assert.Equal(expected, actual);
}
Это мой код UpdateEmployee():
public void UpdateEmployee(EmployeeDto employee)
{
var existingEmployee = _dbContext.Employees.SingleOrDefault(e => e.Id == employee.Id);
if (existingEmployee != null)
{
_dbContext.Employees.AddOrUpdate(employee.ToEntity());
}
else
{
throw new Exception("Employee does not exist");
}
}
Вот как выглядит моя макетная установка. Я использую собственный метод имитации AddOrUpdate:
public static Mock<MockDbSet<Employee>> CreateEmployeeMockSet(List<Employee> data)
{
var mockSet = new Mock<MockDbSet<Employee>>();
mockSet.As<IQueryable<Employee>>().Setup(m => m.Provider).Returns(data.AsQueryable().Provider);
mockSet.As<IQueryable<Employee>>().Setup(m => m.Expression).Returns(data.AsQueryable().Expression);
mockSet.As<IQueryable<Employee>>().Setup(m => m.ElementType).Returns(data.AsQueryable().ElementType);
mockSet.As<IQueryable<Employee>>().Setup(m => m.GetEnumerator()).Returns(data.AsQueryable().GetEnumerator());
mockSet.Setup(d => d.Add(It.IsAny<Employee>())).Callback<Employee>(e => data.Add(e));
mockSet.Setup(d => d.AddOrUpdate(It.IsAny<Employee>())).Callback<Employee>(e => UpdateList(e, data));
mockSet.Setup(d => d.Remove(It.IsAny<Employee>())).Callback<Employee>(e => data.Remove(e));
return mockSet;
}
private static void UpdateList(Employee employee, List<Employee> data)
{
var index = data.FindIndex(e => e.Id == employee.Id);
data[index] = employee;
}
К сожалению, обновление не работает. Я получаю такую ошибку:
Message: Assert.Equal() Failure
↓ (pos 5)
Expected: Homer
Actual: Homer Jay
↑ (pos 5)
Где я ошибаюсь?
@TanvirArjel Я отредактировал вопрос, извините за это
Это проект ASP.NET Core?
@TanvirArjel Это .NET framework 4.6.1





Это похоже на случай, когда вы тестируете свой макет, который идет слишком глубоко. Макет - это граница. Он должен подтверждать взаимодействие с имитируемым сервисом, а не заменять его.
Во-первых, предупреждающий знак: AddOrUpdate предназначен для миграции данных, а не для производственного кода. Вы можете ввести побочные эффекты, если передадите ему неполный объект. (стирание данных)
Например, если бы я издевался над DbSet или Repository, я бы посмотрел на:
Получение объекта из макета, а затем проверка того, записал ли этот макет обновление, проверяет макет, а не служебный код, который должен тестироваться.
Спасибо за информацию. Один вопрос: вы сказали, что мне не следует использовать AddOrUpdate в производственной среде. Что мне тогда использовать?
Ваше приложение должно отслеживать, имеете ли вы дело с новым сценарием сущности или обновлением существующего, и обрабатывать эти сценарии отдельно. В случае обновления следует также учитывать версию строки (отметку времени и т. д.), Чтобы обнаруживать изменения в устаревших данных. (данные обновлены другим пользователем / процессом после того, как для этого обновления было выполнено «чтение») Re: риски AddOrUpdate: michaelgmccarthy.com/2016/08/24/…
Где в коде ваш метод
UpdateEmployee?