Mock Microsoft Application Insights API - unit-testing

I have an application which writes to App INsights using custom traces/metrics and also using REST API for reading data on to dashboard.
My questions is for my unit testing can I mock both custom traces(TelemetryClient) and REST API?
I see REST API has a DEMO version but provides random information. It would be helpful if i could setup a DEMO instrumentation key to write to and read from it for unit testing. Let me know.

My proffered approach would be (as for any external component) to create some sort of wrapper around Telemetry Client and then it would be easy to mock it or replace it later if needed.
The other approach I would try is to use TelemetryClient constructor overload with TelemetryConfiguration and mock TelemetryChannel.
var client = new TelemetryClient(
new TelemetryConfiguration
{
TelemetryChannel = new MOCK...
});

Application Insights has an example of mocking TelemetryClient by using a StubTelemetryChannel.
var configuration = new TelemetryConfiguration();
this.sendItems = new List<ITelemetry>();
configuration.TelemetryChannel = new StubTelemetryChannel { OnSend = item => this.sendItems.Add(item) };
configuration.InstrumentationKey = Guid.NewGuid().ToString();
configuration.TelemetryInitializers.Add(new OperationCorrelationTelemetryInitializer());
this.telemetryClient = new TelemetryClient(configuration);

Instead of mocking things out, it might be better to go with your second idea and actually create another application insights resource, and use the instrumentation key for that resource in the unit tests. there's a blog post with information about using multiple environments that should head you in the right direction.
I'd suggest you even do something like that for developer/debug builds as well, so that only your "production" telemetry goes to your real instance, and then all dev/test telemetry goes to another resource instead.

Related

Unit Testing Azure Functions with HttpRequestMessage

I'm running into a few issues when trying to unit test HTTP Trigger Azure Functions in Visual Studio. I've created a GitHub repo (https://github.com/ericdboyd/TestingAzureFunctions) with an example solution that contains both an Azure Function project and a Unit Test project that demonstrates the issues.
First, when I bring in Microsoft.AspNet.WebApi.Core it creates a conflict between System.Web.Http and Microsoft.AspNetCore.Mvc.WebApiCompatShim when trying to use IContentNegotiator. The only way around that was to alias WebApiCompatShim in the csproj file for the test project using the following:
<Target Name="ChangeAliasesOfStrongNameAssemblies" BeforeTargets="FindReferenceAssembliesForReferences;ResolveReferences">
<ItemGroup>
<ReferencePath Condition="'%(FileName)' == 'Microsoft.AspNetCore.Mvc.WebApiCompatShim'">
<Aliases>webapicompatshim</Aliases>
</ReferencePath>
</ItemGroup>
Once I got past that error, I run into this issue which I haven't been able to get past. Using the HttpRequestMessage.CreateResponse extension method to return a response in the Azure Function, I get "No service for type 'System.Net.Http.Formatting.IContentNegotiator' has been registered." when I try to test it. I have tried to build a HttpRequestMessage that I think should work with that extension method using the following code which can also be found in the GitHub repo, but it fails, and I have worked on trying to get past this for several hours now.
IServiceCollection services = new ServiceCollection();
services.AddOptions();
services.AddSingleton(typeof(IContentNegotiator), typeof(DefaultContentNegotiator));
IServiceProvider serviceProvider = services.BuildServiceProvider();
var httpContext = new DefaultHttpContext {RequestServices = serviceProvider};
var httpConfiguration = new HttpConfiguration();
HttpRequestMessage request = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = new Uri(url),
Content = new StringContent(content, Encoding.UTF8, "application/json"),
Properties =
{
{ HttpPropertyKeys.HttpConfigurationKey, httpConfiguration },
{ nameof(HttpContext), httpContext}
}
};
If I don't use that CreateResponse extension method, and just create HttpResponseMessage objects, it works fine.
Just to set some additional context, I know this is not the best way to unit test the code being executed by the Azure Function. I'm unit testing that code much more granularly. But I want to be able to unit test the Azure Function that is performing the mapping between the http request and response to that logic.
There are two Azure Functions and two unit tests in the GitHub repo, one set with the extension method, one without to demonstrate the issue. But everything else is the same.
Not a direct answer to your problem, but it should help you go forward.
You are using Azure Functions v2 - .NET Standard version. This version is currently in beta, so it's a bit shady territory: the documentation is missing and some issues exist.
In V2 you are advised to use HttpRequest class and IActionResult instead of 'classic' HttpRequestMessage and HttpResponseMessage. The default template has a signature like this:
public static IActionResult Run(
[HttpTrigger(AuthorizationLevel.Function, "get")] HttpRequest req, TraceWriter log)
This should enable you to get rid of your shim and to unit test the functions similar to ASP.NET Core way.
Specify the jsonformatter while responding as below
req.CreateResponse(HttpStatusCode.OK, $"Hello, {name}", new JsonMediaTypeFormatter())

Mocking a dependency in Node

I'm in the process of learning Node.js and am wondering about how people mock dependencies in their modules when unit testing.
For example:
I have a module that abstracts my MongoDB calls. A module that uses this module may start out something like this.
var myMongo = require("MyMongoModule");
// insert rest of the module here.
I want to ensure I test such a module in isolation while also ensuring that my tests don't insert records/documents into Mongo.
Is there a module/package that I can use that proxies require() so I can inject in my own mocks? How do other's typically address this issue?
You can use a dependency injection library like nCore
To be honest, the hard part of this is actually mocking out the mongoDB API, which is complex and non trivial. I estimate it would take about a week to mock out most of the mongo API I use so I just test againts the a local mongodb database on my machine (which is always in a weird state)
Then with nCore specific syntax
// myModule.js
module.exports = {
myMethod: function () {
this.mongo.doStuff(...)
},
expose: ["myMethod"]
};
// test-myModule.js
var module = require("myModule")
module.mongo = mongoMock
assert(module.myMethod() === ...)
After reviewing Ryanos's suggestion as well as the Horaa package on npm, I discovered this thread on the Google Group that pointed me towards Sandboxed-Module.
Sandboxed-Module allows me to inject/override require() without me having to expose such dependencies for my unit tests.
I'm still up for other suggestions; however, Sandboxed-Module appears to fit my needs at the moment.
You easily mock require by using "a": https://npmjs.org/package/a
e.g. need to mock require('./foo') in unit test:
var fakeFoo = {};
var expectRequire = require('a').expectRequire;
expectRequire('./foo).return(fakeFoo);
//in sut:
var foo = require('./foo); //returns fakeFoo
Overwriting require to inject your mocks is a possible solution. However, I concur in Raynos' opinion:
I personally find the methodology of overwriting require on a file by file basis an "ugly hack" and prefer to go for proper DI. It is however optimum for mocking one or two modules on an existing code base without rewriting code for DI support.
To use proper dependency injection not only saves you an "ugly hack" but also allows you to apply additional use cases apart from injecting mocks. In production you may e.g. usually instantiate connections over http and in certain circumstances inject a different implementation to establish a connection over VPN.
If you want to look for a dependency injection container read this excellent article and check out Fire Up! which I implemented.

How do I use an API of a windows service?

I've got a big windows service application. It performs actions on a time bound basis. Sometimes I need to be able to use some of it's functionality in isolation from the rest of the application. Currently I've got a battery of 'unit tests' which call into various sources and perform the desired functionality. My problem is these are not unit tests, they are the way we're exposing the API. If we run all the unit tests in the project, we'll be damaging some of our production data.
My question is how do I go about accessing some of the functionality of the application without unit testing? I was thinking of perhaps something like an interpreter over the top of it where you can call various parts of the functionality, but am not really that sure where to start.
An example of a unit test in our code will be:
[TestMethod]
public void TransferFunds()
{
int accountNumberTo = 123456;
int accountNumberFrom = 654321;
var accountFrom = Store.GetAccount(accountNumberFrom);
var accountTo = Store.GetAccount(accountNumberTo);
double amountToTransfer = 1000;
DateTime transactionDate = new DateTime(2010,01,01);
Store.TransferFunds(accountFrom, AccountTo, amountToTransfer, transactionDate);
var client = BankAccountService.Client();
client.Contribute(accountNumberTo, amountToTransfer, transactionDate);
client.Contribute(accountNumberFrom, amountToTransfer, transactionDate);
}
How can we move this out of unit tests, but still have the ability to run code like this?
Your setup sounds very dangerous. I would create separate console applications for your different needs. I would also remove recommend that you remove all unittests that endangers your production data. Having that sort of unittests is just down-right bad!

Factory pattern for test and live web services

Can web services be used in a factory pattern given that the code is auto-generated and I do not want to alter it (to add a base class for example)?
A reason to do this would be if you had 2 web services that were identical but one was for test data and one was for live data and you wanted to switch between the services based on the environment the code was runnig in.
[Edit]
I am using C# 3.
If you're using C# and SOAP, you can change the destination at runtime:
var webSvc = new WebServerObjectName();
webSvc.Url = "http://examples/com/foo.asmx";
//or pull from .config, etc.
webSvc.Url = ConfigurationManager.AppSettings["WebServiceUri"].ToString();
//make the call to the web method
var custs = webSvc.GetCustomerList();
The flow would be:
at design-time, make the web reference. Establish the contract, and code for it (input & output params). You'll only need to make it once, as long as the contract stays the same.
at run-time, change the URL/URI/target of the web service. Obviously it would have to have the same contract/params/method signature, otherwise the call would fail at runtime.
make the call

Strategies to mock a webservice

I'm implementing a client consuming a webservice. I want to reduce dependencies and decided to mock the webservice.
I use mockito, it has the advantage vs. EasyMock to be able to mock classes, not just interfaces. But that's not the point.
In my test, I've got this code:
// Mock the required objects
Document mDocument = mock(Document.class);
Element mRootElement = mock(Element.class);
Element mGeonameElement = mock(Element.class);
Element mLatElement = mock(Element.class);
Element mLonElement = mock(Element.class);
// record their behavior
when(mDocument.getRootElement()).thenReturn(mRootElement);
when(mRootElement.getChild("geoname")).thenReturn(mGeonameElement);
when(mGeonameElement.getChild("lat")).thenReturn(mLatElement);
when(mGeonameElement.getChild("lon")).thenReturn(mLonElement);
// A_LOCATION_BEAN is a simple pojo for lat & lon, don't care about it!
when(mLatElement.getText()).thenReturn(
Float.toString(A_LOCATION_BEAN.getLat()));
when(mLonElement.getText()).thenReturn(
Float.toString(A_LOCATION_BEAN.getLon()));
// let it work!
GeoLocationFetcher geoLocationFetcher = GeoLocationFetcher
.getInstance();
LocationBean locationBean = geoLocationFetcher
.extractGeoLocationFromXml(mDocument);
// verify their behavior
verify(mDocument).getRootElement();
verify(mRootElement).getChild("geoname");
verify(mGeonameElement).getChild("lat");
verify(mGeonameElement).getChild("lon");
verify(mLatElement).getText();
verify(mLonElement).getText();
assertEquals(A_LOCATION_BEAN, locationBean);
What my code shows is that I "micro-test" the consuming object. It's like I would implement my productive code in my test. An example for the result xml is London on GeoNames.
In my opinion, it's far too granular.
But how can I mock a webservice without giving everystep? Should I let the mock object just return a XML file?
It's not about the code, but the approach.
I'm using JUnit 4.x and Mockito 1.7
I think the real problem here is that you have a singleton that calls and creates the web service so it is difficult to insert a mock one.
You may have to add (possibly package level) access to the singleton class. For example if the constructor looks something like
private GeoLocationFactory(WebService service) {
...
}
you can make the constructor package level and just create one with a mocked web service.
Alternatively you can set the webservice by adding a setter method, although I don't like mutable Singletons. Also in that case you have to remember to unset the webservice afterwards.
If the webservice is created in a method you might have to make the GeoLocationFactory extensible to substitute the mock service.
You may also look into remove the singleton itself. There are articles online and probably here on how to do that.
you really want to be mocking the results returned from the webservice to the code that will be using the result. In your example code above you seem to be mocking mDocument but you really want to pass in an instance of mDocument that has been returned from a mocked instance of your webservice and assert that the locationBean returned from the geoLocationFetcher matches the value of A_LOCATION_BEAN.
The easiest option would be to mock the WebService client,
when(geoLocationFetcher.extractGeoLocationFromXml(anyString()))
.thenReturn("<location/>");
You can modify the code to read the response xml from the file system.
Sample code can be found here: Mocking .NET WebServices with Mockito