Search code examples
c#unit-testingmockingmoqsslstream

How to moq a SslStream in unit test?


I would like to mock AuthenticateAsClientAsync method in the SslStream class. I also want to mock the different security cases used by the SslStream for example: IsAuthenticated, IsEncrypted and IsSigned. Mocking seems possible, because the method and the properties are virtual or override.

internal bool AuthenticateSSLStream(SslStream sslStream)
{
    string certName = myCertificate.GetNameInfo(X509NameType.SimpleName, false);
    bool isAuthenticationCompleted = sslStream.AuthenticateAsClientAsync(certName,
        new X509Certificate2Collection(myCertificate), SslProtocols.Tls11 | SslProtocols.Tls12, true).Wait(10000);
    if (!isAuthenticationCompleted || !sslStream.IsAuthenticated || !sslStream.IsEncrypted || !sslStream.IsSigned)
    {
        throw new AuthenticationException("Authentication is not succeeded!");
    }

    return isAuthenticationCompleted;
}

I have created a method and pass a SslStream in order to mock it. A X509Certificate2 certificate was passed through the constructor and stored in the variable name myCertificate.

How can I coverage all cases of the condition? How to reach the authentication exception using moq?


Solution

  • It is possible to mock with the Moq framework. The SslStream constructor accepts a Stream for sending and receiving data.

    • Step one is to create a streamMock.

    • Secondly, create a sslStreamMock and passed the mocked Stream object instance to the sslStreamMock.

    • Next, setup the specific method and property.

        private Mock<SslStream> CreateSslStreamMock(Task task, bool isAuthenticated, bool isEncrypted, bool isSigned)
        {
            Mock<Stream> streamMock = new Mock<Stream>();
            streamMock.SetupGet(s => s.CanRead).Returns(true);
            streamMock.SetupGet(s => s.CanWrite).Returns(true);
      
            Mock<SslStream> sslStreamMock = new Mock<SslStream>(streamMock.Object);
            sslStreamMock.Setup(ss => ss.AuthenticateAsClientAsync(
                It.IsAny<string>(),
                It.IsAny<X509Certificate2Collection>(),
                It.IsAny<SslProtocols>(),
                It.IsAny<bool>())).Returns(task);
            sslStreamMock.SetupGet(s => s.IsAuthenticated).Returns(isAuthenticated);
            sslStreamMock.SetupGet(s => s.IsEncrypted).Returns(isEncrypted);
            sslStreamMock.SetupGet(s => s.IsSigned).Returns(isSigned);
      
            return sslStreamMock;
        }
      

    It is important to streamMock is readable and writable, otherwise SslStream constructor will throw ArgumentException, hence unable to create the mock object instance.