Первое наблюдение состояло в том, что вы передаете поддельное ISocket
в state
и попытаетесь привести его к Socket
в асинхронном обратном вызове, что приведет к нулевой ошибке, что означает, что connectDone.Set()
никогда не вызывается, поэтому WaitOne
не разблокирует.
Измените это на
private void ConnectCallback(IAsyncResult result) {
ISocket client = (ISocket)result.AsyncState;
client.EndConnect(result);
connectDone.Set();
}
Вторым наблюдением было то, что вы неправильно настраивали ложные вызовы.Здесь не нужно размышлять, поскольку вам нужно было получить переданные аргументы из mock и затем вызвать их в настройке обратного вызова mock
Следующее основано на вашем исходном коде.Просмотрите его, чтобы понять, что было объяснено выше.
[TestClass]
public class SocketManagerTests {
[TestMethod]
public void ConnectTest() {
//Arrange
var mockSocket = new Mock<ISocket>();
//async result needed for callback
IAsyncResult mockedIAsyncResult = Mock.Of<IAsyncResult>();
//set mock
mockSocket.Setup(_ => _.BeginConnect(
It.IsAny<EndPoint>(), It.IsAny<AsyncCallback>(), It.IsAny<object>())
)
.Returns(mockedIAsyncResult)
.Callback((EndPoint ep, AsyncCallback cb, object state) => {
var m = Mock.Get(mockedIAsyncResult);
//setup state object on mocked async result
m.Setup(_ => _.AsyncState).Returns(state);
//invoke provided async callback delegate
cb(mockedIAsyncResult);
});
var manager = new SocketManager(mockSocket.Object);
//Act
var actual = manager.Connect();
//Assert
Assert.IsTrue(actual);
mockSocket.Verify(_ => _.EndConnect(mockedIAsyncResult), Times.Once);
}
}
Наконец, я считаю, что вам следует рассмотреть возможность изменения этого кода, чтобы использовать TPL, чтобы обойти весь обратный вызов и драму IAsyncResult
.По сути, раскрытие асинхронного API и упаковка вызовов TaskCompletionSource<T>
, но я думаю, что это выходит за рамки этого вопроса.