Unit Testing in Nancy causing Routebuilder exception using TinyIoc - unit-testing

Getting a System.MissingMethodException, Method not found: 'Void RouteBuilder.set_Item()
Get["/foo"] = parameters => { return Bar(Request);};
This runs fine when calling from browser, but fails when testing with this setup
var browser = new Browser(with =>
{
with.Module<Foobar>();
}
var response = brower.Get("/Foo", with => {with.HttpRequest();});
Any clue why the Routebuilder for testing won't pick up this route?

Turns out I had created the test project using the pre-release version of Nancy.Testing. This in turn made TinyIOC unhappy when trying to build routes/dependencies. So, if you see this mysterious message, check that your working code and test code are referencing the same packages.

Related

ReSharper not supporting Assert.That

I'm in the process of returning to ReSharper recently, using trial of the newest version - 2022.2.3. I've got quite surprised when one of my nUnit tests failed in a weird way, when run by Resharper's built in Unit Test runner. Something that has never happened to me with a Test Explorer.
As long as the Asserts pass, it's all fine - green, all tests are listed. However, when the assert fails, it says One or more child tests had errors. Exception doesn't have a stacktrace
Not only there is no mention of actual values that weren't correct, but the whole failing test seems to be gone!
This happens only when I use the 'modern' approach with Assert.That. So
Assert.That(httpContext.Response.StatusCode, Is.EqualTo(200));
is causing issues, meanwhile, the more classic:
Assert.AreEqual(200, httpContext.Response.StatusCode);
works as expected. Is that something that is a known bug, or maybe some attributes are required? JetBrains claims they have full support of nUnit out of the box, so that is a bit surprising.
NOTE: the tests methods are async, awaiting result and returning Tasks, beside this nothing unusual.
EDIT: The test code is as follows, ApiKeyMiddleware is any middleware that returns response with 200 here.
[TestFixture]
public class ApiKeyMiddlewareTests
{
[Test]
public async Task Invoke_ActiveKey_Authorized()
{
var httpContext = new DefaultHttpContext();
httpContext.Request.Headers.Add("XXXXX", "xxxx");
var configuration = Options.Create(new AccessConfiguration { ActiveApiKeys = new List<string> { "xxxx" } });
var middleware = new ApiKeyMiddleware(GetEmptyRequest(), configuration);
await middleware.Invoke(httpContext);
Assert.That(httpContext.Response.StatusCode, Is.EqualTo(200)); //change to anything else than 200 and it fails + vanishes
}
}

Web Unit Tests not finding Url

I am using aspnetboilerplate 5.1.0.
In the ProjectName.Web.Tests I have run into a situation that I cannot solve.
I have set up web tests for my controller using [Fact] or [Theory].
When I attempt to run the tests using GetResponseAsString(string url, HttpStatusCode expectedStatusCode = HttpStatusCode.OK) found in the webtestbase class. All the tests fail.
Here is an example of my Test:
[Fact]
public async Task Index_Test()
{
//Act
var response = await GetResponseAsStringAsync(
GetUrl<HomeController>(nameof(HomeController.Index))
);
//Assert
response.ShouldNotBeNullOrEmpty();
}
The Tests all fail on this:
Message:
Shouldly.ShouldAssertException : response.StatusCode
should be
HttpStatusCode.OK
but was
HttpStatusCode.NotFound
I have other aspnetboilerplate projects in version 3.8.3 and 4.2.1 and the web tests work just fine. So I'm not sure why the server is not able to find the action methods on my controllers.
The service tests found in the ProjectName.Tests project run just fine.
I found the culprit. The problem I was experiencing was due to attempting to copy a project for web unit tests from one of the aspnetboilerplate project template repositories and updating all of the references and class names to match the names and namespaces in the destination VS solution.
I submitted a similar question on the aspnetboilerplate github account.
https://github.com/aspnetboilerplate/aspnetboilerplate/issues/5463.
Ultimately, here is what happened.
After going through the same process with a newer project. I found that In the
class file that would by default be named AbpProjectNameWebTestBase.cs in the method
protected override IWebHostBuilder CreateWebHostBuilder()
{
return base
.CreateWebHostBuilder()
.UseContentRoot(ContentRootFolder.Value)
.UseSetting(WebHostDefaults.ApplicationKey, typeof(AbpProjectNameWebModule).Assembly.FullName);
}
I mistakenly replaced AbpProjectNameWebModule with AbpProjectNameTestModule instead of AbpProjectNameWebMvcModule. This was trying to use the Application Service Unit test project as the web project. Therefore it could not find any of the referenced URI's and therefore returned httpStatusCode.NotFound.
After fixing this reference. I started getting exceptions that pertained to the public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) method.
These were things like adding app.UseAuthentication() and app.UseAuthorization() as well as needing to add a Middleware to provide a ClaimsIdentity and ClaimsPrincipal for the context.User (i.e. app.UserMiddleware<TestAuthenticationMiddleware>())
Now, I am able to get my web unit tests to run as I had in previous versions.

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

Unit test a polymer web component that uses firebase

I have been trying to configure offline unit tests for polymer web components that use the latest release of Firebase distributed database. Some of my tests are passing, but others—that look nigh identical to passing ones—are not running properly.
I have set up a project on github that demonstrates my configuration, and I'll provide some more commentary below.
Sample:
https://github.com/doctor-g/wct-firebase-demo
In that project, there are two suites of tests that work fine. The simplest is offline-test, which doesn't use web components at all. It simply shows that it's possible to use the firebase database's offline mode to run some unit tests. The heart of this trick is the in the suiteSetup method shown below—a trick I picked up from nfarina's work on firebase-server.
suiteSetup(function() {
app = firebase.initializeApp({
apiKey: 'fake',
authDomain: 'fake',
databaseURL: 'https://fakeserver.firebaseio.com',
storageBucket: 'fake'
});
db = app.database();
db.goOffline();
});
All the tests in offline-test pass.
The next suite is wct-firebase-demo-app_test.html, which test the eponymous web component. This suite contains a series of unit tests that are set up like offline-test and that pass. Following the idea of dependency injection, the wct-firebase-demo-app component has a database attribute into which is passed the firebase database reference, and this is used to make all the firebase calls. Here's an example from the suite:
test('offline set string from web component attribute', function(done) {
element.database = db;
element.database.ref('foo').set('bar');
element.database.ref('foo').once('value', function(snapshot) {
assert.equal(snapshot.val(), 'bar');
done();
});
});
I have some very simple methods in the component as well, in my attempt to triangulate toward the broken pieces I'll talk about in a moment. Suffice it to say that this test passes:
test('offline push string from web component function', function(done) {
element.database = db;
let resultRef = element.pushIt('foo', 'bar');
element.database.ref('foo').once('value', function(snapshot) {
assert.equal(snapshot.val()[resultRef.key], 'bar');
done();
});
});
and is backed by this implementation in wct-firebase-demo-app:
pushIt: function(at, value) {
return this.database.ref(at).push(value);
},
Once again, these all pass. Now we get to the real quandary. There's a suite of tests for another element, x-element, which has a method pushData:
pushData: function(at, data) {
this.database.ref(at).push(data);
}
The test for this method is the only test in its suite:
test('pushData has an effect', function(done) {
element.database = db;
element.pushData('foo', 'xyz');
db.ref('foo').once('value', function(snapshot) {
expect(snapshot.val()).not.to.be.empty;
done();
});
});
This test does not pass. While this test is running, the console comes up with an error message:
Your API key is invalid, please check you have copied it correctly.
By setting some breakpoints and walking through the execution, it seems to me that this error comes up after the call to once but before the callback is triggered. Note, again, this doesn't happen with the same test structure described above that's in wct-firebase-demo-app.
That's where I'm stuck. Why do offline-test and wct-firebase-demo-app_test suites work fine, but I get this API key error in x-element_test? The only other clue I have is that if I copy in a valid API key into my initializeApp configuration, then I get a test timeout instead.
UPDATE:
Here is a (patched-together) image of my console log when running the tests.:
To illustrate the issue brought up by tony19 below, here's the console log with just pushData has an effect in x-element_test commented out:
The offline-test results are apparently false positives. If you check the Chrome console, offline-test actually throws the same error:
The error doesn't affect the test results most likely because the API key validation occurs asynchronously after the test has already completed. If you could somehow hook into that validation, you'd be able to to catch the error in your tests.
Commenting out all tests except for offline firebase is ok shows the error still occurring, which points to suiteSetup(). Narrowing the problem down further by commenting 2 of the 3 function calls in the setup, we'll see the error is caused by the call to firebase.initializeApp() (and not necessarily related to once() as you had suspected).
One workaround to consider is wrapping the Firebase library in a class/interface, and mocking that for unit tests.

unit/integration testing of controllers and views using MvcContrib throws error when run

Am fairly new to the world of testing MVC 4 Web Applications and have been attempting to unit test views and controllers to see whether for a given controller that an action renders a particular view, I have been using MvcContrib TestHelper to try to simply the process of testing the application but so far have been unable to get the test to pass.
When the test is run I receive the error Expected view name was 'index' actual was ''
Currently I am running this test method:
[TestMethod]
public void AMAC_Controller_Renders_Index_View()
{
var builder = new TestControllerBuilder();
var controller = new AMACController();
builder.InitializeController(controller);
var result = controller.Index();
result.AssertViewRendered().ForView("index").WithViewData<AMACEnquiryModel>();
}
the controller and model are both currently in use by the application, was wondering if you could give any advice on how get this test working, I have modified previously when I have done this I get another error that the route name already exists in the collection.
After getting some advice from one of the contributors of the MvcContrib project the reason the test wasn't passing was because I was passing the wrong data into the .ForView(), before I had .ForView("index") where the controller was actually passing View(model) so the value for .ForView() was actually an empty string so the assert now looks like this:
result.AssertViewRendered().ForView("").WithViewData<AMACEnquiryModel>();