Home > Software engineering >  GoogleCloudVision c# - how to unit test the service
GoogleCloudVision c# - how to unit test the service

Time:07-07

I've implemented a Google Cloud Vision service in my backend code. I want to unit test the service but I don't know how to mock it.

Here's my current code that I'm going to mock. Is there a way to inject the ImageAnnotatorClient so I could mock it?

public class GoogleCloudVisionService : IGoogleCloudVision
{
    private readonly GoogleCloudVisionSettings googleCloudVisionSettings;

    private ImageAnnotatorClient client;

    public GoogleCloudVisionService(IOptions<GoogleCloudVisionSettings> googleCloudVisionSettings)
    {
        this.googleCloudVisionSettings = googleCloudVisionSettings.Value.WithParsedKey();

        var credential = GoogleCredential.FromJson(this.googleCloudVisionSettings.ApiJson);

        ImageAnnotatorClientBuilder clientBuilder = new ImageAnnotatorClientBuilder();
        clientBuilder.Credential = credential;

        client = clientBuilder.Build();
    }

    public async Task<SafeSearchAnnotation> GetImageAnnotation(byte[] imageBytes)
    {
        var image = Image.FromBytes(imageBytes);

        var annotation = await client.DetectSafeSearchAsync(image);

        return annotation;
    }

    public async Task<bool> IsImageSafe(byte[] imageBytes)
    {
        var annotations = await GetImageAnnotation(imageBytes);

        var isSafe = annotations.Adult < googleCloudVisionSettings.Annotations.Adult &&
            annotations.Racy < googleCloudVisionSettings.Annotations.Racy &&
            annotations.Violence < googleCloudVisionSettings.Annotations.Violence &&
            annotations.Medical < googleCloudVisionSettings.Annotations.Medical &&
            annotations.Spoof < googleCloudVisionSettings.Annotations.Spoof;

        return isSafe;
    }
}

CodePudding user response:

Finally got a working code after looking some examples in our codebase

public class GoogleCloudVisionServiceUnitTests
{
    private Infrastructure.GoogleCloud.Api api;

    public GoogleCloudVisionServiceUnitTests()
    {
        var faker = new Faker<Infrastructure.GoogleCloud.Api>()
                .RuleFor(x => x.Type, f => f.Random.String2(6))
                .RuleFor(x => x.ProjectId, f => f.Random.String2(6))
                .RuleFor(x => x.PrivateKeyId, f => f.Random.String2(6))
                .RuleFor(x => x.PrivateKey, f => f.Random.String2(6))
                .RuleFor(x => x.ClientEmail, f => f.Random.String2(6))
                .RuleFor(x => x.ClientId, f => f.Random.String2(6))
                .RuleFor(x => x.AuthUri, f => f.Random.String2(6))
                .RuleFor(x => x.TokenUri, f => f.Random.String2(6))
                .RuleFor(x => x.AuthProviderUrl, f => f.Random.String2(6))
                .RuleFor(x => x.ClientCertUrl, f => f.Random.String2(6));

        api = faker.Generate(1).First();
    }

    [Fact]
    public async Task GivenSafeImage_ShouldReturnAnnotations()
    {
        // Arrange
        var faker = new Faker();
        var expectedAnnotation = new SafeSearchAnnotation
        {
            Adult = Likelihood.Likely,
            Racy = Likelihood.Likely,
            Medical = Likelihood.Likely,
            Spoof = Likelihood.Likely,
            Violence = Likelihood.Likely
        };

        var mockOptions = new Mock<ImageAnnotatorClient>();
        mockOptions.Setup(mock => mock.DetectSafeSearchAsync(It.IsAny<Image>(), It.IsAny<ImageContext>(), It.IsAny<CallSettings>()))
            .ReturnsAsync(expectedAnnotation);

        var json = JsonConvert.SerializeObject(api);
        byte[] bytes = Encoding.Default.GetBytes(json);

        var googleCloudVisionSettings = new GoogleCloudVisionSettings
        {
            Key = Convert.ToBase64String(bytes),
            Annotations = new Annotations
            {
                Adult = Likelihood.Likely,
                Racy = Likelihood.Likely,
                Medical = Likelihood.Likely,
                Spoof = Likelihood.Likely,
                Violence = Likelihood.Likely
            }
        };

        // Act
        var googleCloudVisionService = new GoogleCloudVisionService(mockOptions.Object, Options.Create(googleCloudVisionSettings));

        var annotations = await googleCloudVisionService.GetImageAnnotation(faker.Random.Bytes(512));

        // Assert
        annotations.Adult.Should().Be(googleCloudVisionSettings.Annotations.Adult);
        annotations.Racy.Should().Be(googleCloudVisionSettings.Annotations.Racy);
        annotations.Medical.Should().Be(googleCloudVisionSettings.Annotations.Medical);
        annotations.Spoof.Should().Be(googleCloudVisionSettings.Annotations.Spoof);
        annotations.Violence.Should().Be(googleCloudVisionSettings.Annotations.Violence);
    }

    [Fact]
    public async Task GivenSafeImage_ShouldReturnTrue()
    {
        // Arrange
        var faker = new Faker();
        var expectedAnnotation = new SafeSearchAnnotation
        {
            Adult = Likelihood.VeryUnlikely,
            Racy = Likelihood.VeryUnlikely,
            Medical = Likelihood.VeryUnlikely,
            Spoof = Likelihood.VeryUnlikely,
            Violence = Likelihood.VeryUnlikely
        };

        var mockOptions = new Mock<ImageAnnotatorClient>();
        mockOptions.Setup(mock => mock.DetectSafeSearchAsync(It.IsAny<Image>(), It.IsAny<ImageContext>(), It.IsAny<CallSettings>()))
            .ReturnsAsync(expectedAnnotation);

        var json = JsonConvert.SerializeObject(api);
        byte[] bytes = Encoding.Default.GetBytes(json);

        var googleCloudVisionSettings = new GoogleCloudVisionSettings
        {
            Key = Convert.ToBase64String(bytes),
            Annotations = new Annotations
            {
                Adult = Likelihood.Likely,
                Racy = Likelihood.Likely,
                Medical = Likelihood.Likely,
                Spoof = Likelihood.Likely,
                Violence = Likelihood.Likely
            }
        };

        // Act
        var googleCloudVisionService = new GoogleCloudVisionService(mockOptions.Object, Options.Create(googleCloudVisionSettings));

        var isSafe = await googleCloudVisionService.IsImageSafe(faker.Random.Bytes(512));

        // Assert
        Assert.True(isSafe);
    }

    [Fact]
    public async Task GivenUnsafeImage_ShouldReturnFalse()
    {
        // Arrange
        var faker = new Faker();
        var expectedAnnotation = new SafeSearchAnnotation
        {
            Adult = Likelihood.VeryLikely,
            Racy = Likelihood.VeryLikely,
            Medical = Likelihood.VeryLikely,
            Spoof = Likelihood.VeryLikely,
            Violence = Likelihood.VeryLikely
        };

        var mockOptions = new Mock<ImageAnnotatorClient>();
        mockOptions.Setup(mock => mock.DetectSafeSearchAsync(It.IsAny<Image>(), It.IsAny<ImageContext>(), It.IsAny<CallSettings>()))
            .ReturnsAsync(expectedAnnotation);

        var json = JsonConvert.SerializeObject(api);
        byte[] bytes = Encoding.Default.GetBytes(json);

        var googleCloudVisionSettings = new GoogleCloudVisionSettings
        {
            Key = Convert.ToBase64String(bytes),
            Annotations = new Annotations
            {
                Adult = Likelihood.Likely,
                Racy = Likelihood.Likely,
                Medical = Likelihood.Likely,
                Spoof = Likelihood.Likely,
                Violence = Likelihood.Likely
            }
        };

        // Act
        var googleCloudVisionService = new GoogleCloudVisionService(mockOptions.Object, Options.Create(googleCloudVisionSettings));

        var isSafe = await googleCloudVisionService.IsImageSafe(faker.Random.Bytes(512));

        // Assert
        Assert.False(isSafe);
    }
}

To make it mock-able, I need to add a new constructor so I can pass an instance of Mock<ImageAnnotatorClient>

public GoogleCloudVisionService(ImageAnnotatorClient client, IOptions<GoogleCloudVisionSettings> googleCloudVisionSettings)
{
    this.client = client;
    this.googleCloudVisionSettings = googleCloudVisionSettings.Value.WithParsedKey();
}
  • Related