Как проверить результат обработчика событий - PullRequest
1 голос
/ 02 февраля 2020

У меня есть ViewModel, который получает интерфейс с обработчиком событий в конструкторе:

public VehiclesViewModel(IVehicles vehicles)
{
    _vehicles = vehicles;
    VehicleRows = new ObservableCollection<VehicleRowViewModel>();
    _vehicles.ListVehicles("secret", callback);
}

Обратный вызов добавляет все перечисленные транспортные средства в ObservableCollection:

private void callback(object sender, MyAsyncCompletedEventArgs e)
{
    if (e.Result is Vehicle[] vehicles)
    {
        foreach (var vehicle in vehicles)
        {
            VehicleRows.Add(new VehicleRowViewModel {Name = vehicle.Name});
        }
    }
}
public ObservableCollection<VehicleRowViewModel> VehicleRows { get; set; }

Vehicle и VehicleRowViewModels это просто простые классы:

public class VehicleRowViewModel
{
    public string Name { get; set; }
}

public class Vehicle
{
    public string Name { get; set; }
}

Это остальная часть кода:

public interface IVehicles
{
    void ListVehicles(string category, MyAsyncCompletedEventHandler callback);
}

public delegate void MyAsyncCompletedEventHandler(object sender, MyAsyncCompletedEventArgs e);

public class MyAsyncCompletedEventArgs : AsyncCompletedEventArgs
{
    public MyAsyncCompletedEventArgs(Exception ex) : base(ex, true, null)
    {
    }

    public object Result { get; set; }
}

Теперь я хотел бы проверить, правильно ли добавлено количество транспортных средств в VehicleRows:

[TestFixture]
public class VehiclesViewModelTests
{
    [Test]
    public void AllVehiclesFromCallBackEndUpInProperty()
    {
        var vehiclesMock = new Mock<IVehicles>();
        vehiclesMock.Setup(x => x.ListVehicles(It.IsAny<string>(), It.IsAny<MyAsyncCompletedEventHandler>())).Callback<string, MyAsyncCompletedEventHandler>(
            (s, c) =>
            {
                c = (sender, args) =>
                    args.Result = new List<Vehicle>
                    {
                        new Vehicle {Name = "TR3B"},
                        new Vehicle {Name = "Aurora"},
                        new Vehicle {Name = "HAUC"}
                    }.ToArray();
            });
        var testee = new VehiclesViewModel(vehiclesMock.Object);
        Assert.AreEqual(3,testee.VehicleRows.Count);
    }
}

Но тест не пройден. Как я могу имитировать обратный вызов для правильного тестирования ViewModel?

У меня есть репозиторий github с примером: https://github.com/tbremeyer/TestEventHandler.git

1 Ответ

1 голос
/ 02 февраля 2020

В вашем примере теста вы пытаетесь определить делегата в имитированном обратном вызове, когда вы должны вызывать делегата, который был передан в имитированный обратный вызов.

Просмотрите следующий рефакторинг предоставленного вами теста, который захватывает обратный вызов, вызывает его и проверяет ожидаемое поведение

[Test]
public void AllVehiclesFromCallBackEndUpInProperty() {
    //Arrange
    MyAsyncCompletedEventHandler handler = null;

    var vehiclesMock = new Mock<IVehicles>();
    vehiclesMock
        .Setup(_ => _.ListVehicles(It.IsAny<string>(), It.IsAny<MyAsyncCompletedEventHandler>()))
        .Callback<string, MyAsyncCompletedEventHandler>((secret, callback) => {
            //capture the delegate for later use;
            handler = callback;
        });

    var subjectUnderTest = new VehiclesViewModel(vehiclesMock.Object);
    //check to make sure the hanler as been set at this point
    Assert.IsNotNull(handler);

    var vehicles = new List<Vehicle> {
        new Vehicle {Name = "TR3B"},
        new Vehicle {Name = "Aurora"},
        new Vehicle {Name = "HAUC"}
    }.ToArray();
    int expected = vehicles.Length;
    var eventArgs = new MyAsyncCompletedEventArgs(null) {
        Result = vehicles
    };

    //Act (invoke the delegate)
    handler.Invoke(vehiclesMock.Object, eventArgs);

    //Assert
    int actual = subjectUnderTest.VehicleRows.Count;
    Assert.AreEqual(expected, actual);
}

Этот тест лучше отражает реальное поведение испытуемого.

...