Насмешливые универсальные асинхронные вызовы WCC ClientChannelWrapper - PullRequest
4 голосов
/ 26 февраля 2011

Недавно я разработал приложение Silverlight, которое использует Mark J Millers ClientChannelWrapper<T> для связи с сервисным уровнем WCF (эффективно уничтожая ссылку на сервис и упаковывая IClientChannel и ClientChannelFactory). Вот интерфейс:

public interface IClientChannelWrapper<T> where T : class
{
    IAsyncResult BeginInvoke(Func<T, IAsyncResult> function);
    void Dispose();
    void EndInvoke(Action<T> action);
    TResult EndInvoke<TResult>(Func<T, TResult> function);
}

Оболочка в основном берет общий интерфейс асинхронного сервиса (который мог быть создан с помощью slsvcutil или вручную созданным после WCF ServiceContract) и упаковывает вызовы, чтобы в случае сбоя канала создать новый канал. Типичное использование выглядит следующим образом:

 public WelcomeViewModel(IClientChannelWrapper<IMyWCFAsyncService> service)
    {
        this.service = service;
        this.synchronizationContext = SynchronizationContext.Current ?? new SynchronizationContext();
        this.isBusy = true;
        this.service.BeginInvoke(m => m.BeginGetCurrentUser(new AsyncCallback(EndGetCurrentUser), null));
    }

private void EndGetCurrentUser(IAsyncResult result)
    {
        string strResult = "";
        service.EndInvoke(m => strResult = m.EndGetCurrentUser(result));
        this.synchronizationContext.Send(
                    s =>
                    {
                        this.CurrentUserName = strResult;
                        this.isBusy = false;
                    }, null);
    }

Все работает нормально, но теперь я бы хотел провести модульное тестирование моделей вида, использующих ClientChannelWrapper. Я настроил простой модульный тест, используя Moq:

[TestMethod]
    public void WhenCreated_ThenRequestUserName()
    {
        var serviceMock = new Mock<IClientChannelWrapper<IMyWCFAsyncService>>();
        var requested = false;

        //the following throws an exception
        serviceMock.Setup(svc => svc.BeginInvoke(p => p.BeginGetCurrentUser(It.IsAny<AsyncCallback>(), null))).Callback(() => requested = true);


        var viewModel = new ViewModels.WelcomeViewModel(serviceMock.Object);
        Assert.IsTrue(requested);
    }

Я получаю NotSupportedException:

Неподдерживаемое выражение: p => p.BeginGetCurrentUser (IsAny (), null).

Я довольно новичок в Moq, но, думаю, есть проблема с ClientChannelWrapper, использующим универсальные интерфейсы сервиса. Попытка обернуть мою голову вокруг этого в течение довольно долгого времени, возможно, у кого-то есть идея. Спасибо.

1 Ответ

3 голосов
/ 27 февраля 2011

Извините, что отвечаю на мой вопрос, но я, наконец, получил его.Вот подробности:

Как часто, решение было прямо передо мной, так как оно было в конкретной реализации Марка Дж. Миллера IClientChannelWrapper.Там он предоставляет два конструктора, один из которых принимает строку имени конечной точки WCF (которую я использую в рабочем коде), а второй:

public ClientChannelWrapper(T service)
    {
        m_Service = service;
    }

Без лишних слов, вот мой новый тестовый код:

[TestMethod]
    public void WhenCreated_ThenRequestUserName()
    {
        var IMySvcMock = new Mock<IMyWCFAsyncService>();
        var serviceMock = new ClientChannelWrapper<IMyWCFAsyncService>(IMySvcMock.Object);
        var requested = false;

        IMySvcMock.Setup(svc => svc.BeginGetCurrentUser(It.IsAny<AsyncCallback>(), null)).Callback(() => requested = true);
        var viewModel = new ViewModels.WelcomeViewModel(serviceMock);

        Assert.IsTrue(requested);
    }

Поэтому я в основном игнорирую интерфейс ChannelWrapper и создаю новый его экземпляр с помощью Mock Object моего интерфейса службы WCF.Затем я настраиваю вызов службы, которая будет использоваться в конструкторе моей модели представления, как показано выше.Теперь все работает как шарм.Я надеюсь, что это будет полезно для кого-то, так как я думаю, что идея ClientChannelWrapper отлично подходит для связи Silverlight <-> WCF.Пожалуйста, не стесняйтесь комментировать это решение!

...