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();
}