Макет DbSet AddOrUpdate не удается обновить мой объект - PullRequest
0 голосов
/ 12 января 2019

У меня есть этот модульный тест. Он проверяет метод 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)

Где я иду не так?

1 Ответ

0 голосов
/ 14 января 2019

Это похоже на случай, когда вы тестируете свой макет, который идет слишком глубоко. Макет это граница. Он должен утверждать взаимодействие с поддельным сервисом, а не заменять его.

Во-первых, предупреждающий знак: AddOrUpdate предназначен для переноса данных, а не рабочего кода. Вы можете ввести побочные эффекты, если вы когда-нибудь передадите его неполной сущности. (стирание данных)

Например, если бы я издевался над DbSet или репозиторием, я бы посмотрел на:

  • Макет DbSet / Repo, чтобы он возвращал мне известное состояние для моего тестового сценария. (работник, ничего, исключение)
  • Утвердить, что SaveChanges вызывали или нет? (да, когда я вернул сотрудника, нет, если во время получения не было возвращено ни одного сотрудника или сценария исключения, мой сервис соответствующим образом вызвал SaveChanges?)
  • Утверждать поведение, если SaveChanges выдает исключение. (Что должен делать мой сервис?)

Получение объекта из макета, а затем проверка того, записало ли это макет обновление, проверяет макет, а не служебный код, который должен тестироваться.

...