Unit Testing ODataQueryOptions Gives MissingMethodException DependencyInjection - unit-testing

So here is my problem, I have an OData Web Api service that uses ODataQueryOptions to filter data from our sql server and I am trying to setup a .Net Framework Unit Test project to test the controllers with different query options. I have been searching for several days now and found many examples but most of them use an older version of OData. This example is the best one I have found so far, the only problem is that calling config.EnableDependencyInjection(); gives me the following exception:
Method not found: 'System.IServiceProvider Microsoft.Extensions.DependencyInjection.ServiceCollectionContainerBuilderExtensions.BuildServiceProvider(Microsoft.Extensions.DependencyInjection.IServiceCollection)'.
Here is an example of my code:
using System.Collections.Generic;
using System.Web.Http.Results;
using System.Web.OData;
using System.Web.OData.Query;
using System.Net.Http;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using University.API.OData.Controllers;
using University.API.OData.Models;
using System.Web.OData.Routing;
using System.Web.Http;
using System.Web.OData.Extensions;
[TestClass]
public class SalesforceUnitTest
{
private HttpRequestMessage request;
private ODataQueryOptions<Product> _options;
[TestInitialize]
public void TestInitialize()
{
request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/odata/product?$top=5");
var model = WebApiConfig.GetModel();
HttpConfiguration config = new HttpConfiguration();
config.EnableDependencyInjection(); //Throws Missing Method Exception
WebApiConfig.Register(config);
config.EnsureInitialized();
request.SetConfiguration(config);
ODataQueryContext context = new ODataQueryContext(
model,
typeof(Product),
new ODataPath(
new Microsoft.OData.UriParser.EntitySetSegment(
model.EntityContainer.FindEntitySet("product"))
)
);
_options = new ODataQueryOptions<Product>(context, request);
}
[TestMethod]
public void ProductTest()
{
var controller = new ProductController();
controller.Request = request;
var response = controller.Get(_options);
var contentResult = response as OkNegotiatedContentResult<List<Product>>;
Assert.IsNotNull(contentResult);
Assert.IsNotNull(contentResult.Content);
}
}
Let me know if there is any other information you may need.
Thank you for any help you can provide.
EDIT:
Here what is referenced in the unit test project:
EntityFramework
EntityFramework.SqlServer
Microsoft.Data.Edm
Microsoft.Data.OData
Microsoft.Extensions.DependencyInjection
Microsoft.Extensions.DependencyInjection.Abstractions
Microsoft.OData.Core
Microsoft.Odata.Edb
Microsoft.Spatial
Microsoft.Threading.Tasks
Microsoft.Threading.Tasks.Extensions
Microsoft.Threading.Tasks.Extensions.Desktop
Microsoft.VisualStudio.TestPlatform.TestFramework
Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions
System
System.ComponentModel.DataAnnotations
System.Net
System.Net.Http
System.Net.Http.Extensions
System.Net.Http.Primitives
System.Net.Http.WebRequest.
System.Spatial
System.Web
System.Web.Http
System.Web.OData
ODataAPI

I figured it out after some more digging. It seems that my Unit Test project was using a different version than my ODataApi project. This for some weird reason was causing the MissingMethodException instead of a VersionMismatchException. Hopefully this helps someone else who is looking into why Dependency Injection isnt working for your Unit Test project.

Related

How to unit test a single conversational statement

i am working with bots and the Microsoft Bot Framework.
I used the DispatchBot template to generate my bot. (https://learn.microsoft.com/de-de/azure/bot-service/bot-builder-tutorial-dispatch?view=azure-bot-service-4.0&tabs=cs)
For conversational testing, i want to create unit tests. Therefore i used this documentation to gather some informations (https://learn.microsoft.com/de-de/azure/bot-service/unit-test-bots?view=azure-bot-service-4.0&tabs=csharp)
The thing is that i dont want to test dialogs, but a single statement (a question and the right answer)
How can i implement this?
Here you can see the Start of my Dispatchbot.cs file where the magic happens (search of the correct Knowledge Base etc.)
Here's a link to how we create tests for CoreBot. The part you're most likely interested in is testing things under the /Bots directory. Based off of the test code you can find there, you likely want something like:
using System;
using System.Threading;
using System.Threading.Tasks;
using CoreBot.Tests.Common;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.BotBuilderSamples.Bots;
using Microsoft.Extensions.Logging;
using Moq;
using Xunit;
namespace KJCBOT_Tests
{
public class BotTests
{
[Fact]
public async Task TestResponseToQuesion()
{
// Note: this test requires that SaveChangesAsync is made virtual in order to be able to create a mock.
var memoryStorage = new MemoryStorage();
var mockConversationState = new Mock<ConversationState>(memoryStorage)
{
CallBase = true,
};
var mockUserState = new Mock<UserState>(memoryStorage)
{
CallBase = true,
};
// You need to mock a dialog because most bots require a Dialog to instantiate it.
// If yours doesn't you can likely skip this
var mockRootDialog = SimpleMockFactory.CreateMockDialog<Dialog>(null, "mockRootDialog");
var mockLogger = new Mock<ILogger<DispatchBot<Dialog>>>();
// Act
var sut = new DispatchBot<Dialog>(mockConversationState.Object, mockUserState.Object, mockRootDialog.Object, mockLogger.Object);
var testAdapter = new TestAdapter();
var testFlow = new TestFlow(testAdapter, sut);
await testFlow
.Send("<Whatever you want to send>")
.AssertReply("<Whatever you expect the reply to be")
.StartTestAsync();
}
}
}

ASP.net core integration testing with inherited Startup class. Unable to locate View

I am attempting to write some integration tests against aspnet core 2.2. I want to use a TestStartup class that inherits from the normal Startup class to configure resources and services for testing purposes.
A simple example (can be found here: https://github.com/davidgouge/aspnet-integration-testing):
I have a solution that contains two projects:
IntegrationTestingWeb (a barebones aspnet mvc app)
IntegrationTestingTests (a testing project)
I have a test that uses the Web Startup class and asserts that OK is returned from /Home/Privacy
[Test]
public async Task GetPrivacy_Through_Normal_Startup()
{
var builder = new WebHostBuilder().UseStartup<Startup>();
var client = new TestServer(builder).CreateClient();
var result = await client.GetAsync("/Home/Privacy");
result.StatusCode.Should().Be(HttpStatusCode.OK);
}
This test passes.
If I create a TestStartupInTestProject class that inherites from Startup but place it in the Tests project, then I have to do some extra work when creating the WebHostBuilder but then the test fails.
[Test]
public async Task GetPrivacy_Through_Test_Startup_In_Test_Project()
{
var builder = new WebHostBuilder().ConfigureServices(services =>
{
var startupAssembly = typeof(TestStartupInTestProject).GetTypeInfo().Assembly;
var manager = new ApplicationPartManager();
manager.ApplicationParts.Add(new AssemblyPart(startupAssembly));
manager.ApplicationParts.Add(new AssemblyPart(typeof(HomeController).Assembly));
manager.FeatureProviders.Add(new ControllerFeatureProvider());
manager.FeatureProviders.Add(new ViewComponentFeatureProvider());
services.AddSingleton(manager);
}).UseStartup<TestStartupInTestProject>();
var client = new TestServer(builder).CreateClient();
var result = await client.GetAsync("/Home/Privacy");
result.StatusCode.Should().Be(HttpStatusCode.OK);
}
The error in the failure is:
Tests.Tests.GetPrivacy_Through_Test_Startup_In_Test_Project
System.InvalidOperationException : The view 'Privacy' was not found. The
following locations were searched:
/Views/Home/Privacy.cshtml
/Views/Shared/Privacy.cshtml
/Pages/Shared/Privacy.cshtml
So it looks like because my Startup class is located in the Test project, the views cannot be located. What setting am I missing to be able to find the Views?
It turns out I was missing .UseContentRoot(Directory.GetCurrentDirectory() + "\\..\\..\\..\\..\\IntegrationTestingWeb") when creating the WebHostBuilder. As it sounds, it sets the root dir where the app will look for Views etc.

Mocking Umbraco Context - GetUmbracoContextWithRouteData Method on UmbracoContextHelper class Missing

Is there an alternative method for GetUmbracoContextWithRouteData() on the UmbracoContextHelper class (Umbraco.Tests assembly) in Umbraco v7.3.4?
I need to mock an instance of IUmbracoContext on my Unit Tests, which I could do previously with the Umbraco.Tests.dll on v7.2.8, but this method has disappeared from the same dll after upgrading to v7.3.4.
This is the my code currently:
var umbracoContextHelper = new UmbracoContextHelper();
var umbracoContext = UmbracoTests.GetUmbracoContextWithRouteData("http://rb.com", 0);
_umbracoContextMock = new Mock<IUmbracoContext>();
_umbracoContextMock.Setup(x => x.Current).Returns(() => umbracoContext);
Is there a different way of doing this in v.7.3.4?
Thanks in advance for your help.
In 7.3, the EnsureUmbracoContext method was enhanced so that doing this should no longer be necessary. See https://github.com/garydevenay/Umbraco-Context-Mock for an example of how to mock out UmbracoContext in 7.3.

Why doesn't `DefaultNancyBoostrapper` find my NancyModule

I'm just getting my feet wet in Nancy. I was really excited to see the Testing process in the Wiki, but when I tried the following I couldn't get it work pass the tests at first.
Using VS2010
Created Empty ASP.NET Web Application Project: Notify.App
Install-Package Nancy.Hosting.AspNet
Created simple Module as listed below: NotifyModule
Created Class Library Project: Notify.UnitTests
Install-Package Nancy.Testing
Install-Package XUnit
Created simple first test: BaseUrlSpec.cs
Using DefaultNancyBootstrapper the test fails with HttpStatusCode.NotFound.
If I replace the bootstrapper definition with:
var bootstrapper = new ConfigurableBootstrapper(
with =>
with.Module<NotifyModule>());
then the test passes. I don't understand why the SDHP using the DefaultNancyBootstrapper didn't work? Did I do something wrong to make it break, or am I missing details in my understanding?
NotifyModule
using Nancy;
public class NotifyModule : NancyModule {
public NotifyModule() {
Get["/"] = _ => HttpStatusCode.OK;
}
}
BaseUrlSpec
using Nancy;
using Nancy.Testing;
using Notify.App;
using Xunit;
public class BaseUrlSpec
{
[Fact]
public void ShouldRespondOk()
{
var bootstrapper = new DefaultNancyBoostrapper();
var app = new Browser(bootstrapper);
var response = app.Get("/", with => with.HttpRequest());
var statusCode = response.StatusCode;
Assert.Equal(HttpStatusCode.OK, statusCode);
}
}
You need to make sure the assembly containing your route is loaded. Referencing a type from your assembly ensures this, therefore the version using the configurable bootstrapper works.
To make the other one work, just add a reference to some type from your assembly. No need to instantiate it.

MVCContrib TestHelper and User.Identity.Name, Server.MapPath and Form Collection

I am new to MVCContrib Testhelper and mocking with Rhino.
I am needing assistance with unit testing a controller which relies on User.Identity.Name, Server.MapPath and Form Collection.
I started off with
var controller = new SubmitController();
var builder = new TestControllerBuilder();
builder.InitializeController(controller);
I found this post for setting User.Identity.Name
controller.ControllerContext = TestHelper.MockControllerContext(controller).WithAuthenticatedUser("domain\\username");
At this point, in my controller i am now able to get to the User.Identity. The problem then became how to i set Form Collection variables. Setting
builder.Form.Add("testvar","1");
no longer worked. It seemed that now I had to access via
controller.HttpContext.Request.Form.Add("testvar","1)
This seemed to work, but at this point, i was no longer using builder(TestControllerBuilder) above.
I then had to mock Server which raised up more issues. How can I continue to use builder but use mocks or stubs for httpContext, HttpRequest, Server etc. I was sort of expecting that builder would have methods for setting expected values for HttpRequest, Server etc.
Thanks
When you replaced the controller's ControllerContext that removed the MVCContrib context. Try something like this:
using MvcContrib.TestHelper;
using MvcContrib.TestHelper.Fakes;
using Rhino.Mocks;
...
var builder = new TestControllerBuilder();
builder.Form.Add("testvar", "1");
builder.HttpContext.User = new FakePrincipal(new FakeIdentity("UserName"), new string[] { "Role" });
builder.HttpContext.Server.Stub(x => x.MapPath(Arg<string>.Is.Anything)).Return("Value");
builder.InitializeController(controller);