I would like to unit test my ValidationFeature rulesets in my ServiceStack project however the plugin is not being initialized when creating my appHost object.
Here is my original code to initialize the appHost.
[TestFixtureSetUp]
private void TestFixtureSetUp()
{
appHost = new BasicAppHost().Init();
appHost.Plugins.Add(new ValidationFeature());
var container = appHost.Container;
container.RegisterValidators(typeof(ApplicationValidator).Assembly);
container.RegisterAutoWiredAs<FakeRetailReferralRepository, IRetailReferralRepository>();
container.RegisterAutoWired<SubmitApplicationService>();
}
I've tried moving the Plugins.Add line in between the BasicAppHost constructor and Init() and that didn't work either. Is what I'm trying to do possible?
The validation feature is validated within the Request Pipeline so would typically require a full integration test to test it, i.e. using a self-host and service client.
You can still unit test a validator, but as validation occurs before the Service is called you would need to test the validator with the Request DTO directly instead of calling the Service, e.g:
using (var appHost = new BasicAppHost
{
ConfigureAppHost = host => {
host.Plugins.Add(new ValidationFeature());
},
ConfigureContainer = c => {
c.RegisterValidators(typeof(ApplicationValidator).Assembly);
}
}.Init())
{
var myValidator = appHost.TryResolve<IValidator<MyRequest>>();
var result = myValidator.Validate(new MyRequest { ... });
Assert.That(result.IsValid, Is.False);
Assert.That(result.Errors.Count, Is.EqualTo(1));
}
Related
How can I test in asp.net core 2.0 following method which exists in separate project than my test project? for example like this:
public partial class LoanRequestServiceController : BaseServiceController
{
public ServiceDTO<AP_CBO> AddCBO(AP_CBO cbo)
{
ServiceDTO<AP_CBO> dto = new ServiceDTO<AP_CBO>();
try
{
using (var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.Snapshot }))
{
cbo.ID_CBO = 333;
dto.Data = cbo;
scope.Complete();
}
}
catch (Exception ex)
{
dto.Error = new ServiceError(ex);
Globals.Logger.Error(ex);
}
finally
{
//Globals.CastleComponentsContainer.Release(LoanRequestDAL);
}
return dto;
}
}
I tested some "light" methods such as if service method returns SucessCode and it works.
Here is my test class:
[Theory]
[InlineData("/Sample/AddCBO")]
public async Task Test_AddCBO(string url)
{
//Arrange
var client = _factory.CreateClient();
//Act
var response = await client.GetAsync(url);
//Assert
response.EnsureSuccessStatusCode();
//Compare two dto objects AP_CBO
//object expected = new AP_CBO { properties... }
// object responseObject = response.Content...
//Assert.Equal(expected, responseObject);
}
I don't know how to test an object with muliple properties.
Maybe I need to use Moq? Theoretically, this method would be go to the DAL (DatabaseAccess Layer) and return from database packed object and returns to the api, or in my case back into test.
First off, you have to decide which level of tests you want to write.
If you're writing a Unit test, you should mock any and all external integrations (in your case I can identify HTTP request -> Controller and Controller -> Database). This is the foundation of your functional testing. So if you're writing unit tests, yes, you should use a mocking framework such as NSubstitute or Moq (and only test your method's behavior by calling it).
The test sample you posted looks to me like an integration test since you're including the integration HTTP request -> Controller. In this case I would seed the database with data (if relevant) and actually call your API endpoint (as you're already doing).
To check the content (DTO) of the response in ASP.Net Core you have to do the following:
// ...
var response = await client.GetAsync(url);
response.EnsureSuccessStatusCode();
var content = await httpResponseMessage.Content.ReadAsStringAsync();
var serviceDto = JsonConvert.DeserializeObject<ServiceDTO<AP_CBO>>(content); // Only for Json
// Validate serviceDto
It is pretty long topic for detailed explanation here ; i think it will be better if you follow a sample and read the details.
I assume that you are going to write unit test; for unit test i can recommend this tutorial that may help you . check this please
I have two Asp.Net Core systems, which are completely independent, meaning that they reside on different web domains. Still, they are in the same solution in Visual Studio. Both Asp.Net Core systems would be hosted, for example, on these two domains:
https://client-localhost:8080 and https://api-localhost:8081
where the client app makes calls to many different routes of the Api domain in order to get data.
I have no problems doing integration tests (using NUnit) for the Api system, for example:
// Integration Test for the Api
[TestFixture]
class IntegrationTestShould
{
public TestServer GetTestServerInstance()
{
return new TestServer(new WebHostBuilder()
.UseStartup<TestServerStartup>()
.UseEnvironment("TestInMemoryDb"));
}
[Test]
public async Task ReturnProductDataFromTestInMemoryDb()
{
using (var server = GetTestServerInstance())
{
var client = server.CreateClient();
var response = await client.GetAsync("/products"); // equivalent to: https://api-localhost:8081/products
var responseString = await response.Content.ReadAsStringAsync();
Assert.AreEqual("{ Shows product data coming from the Api }", responseString);
}
}
}
In order to do a proper integration test for the client app, I would like to make Api calls from the client app to the Api.
Is it possible to create one single test method in which I can start both test servers (client and Api) and consume the api through my client?
I can imagine, for example, to inject the Api test server into the client test server so that I can consume the Api through my client app.
Does something like the following exist?
// Integration test for the client that relies on the Api
[TestFixture]
class IntegrationTestShould
{
public TestServer GetApiTestServerInstance()
{
return new TestServer(new WebHostBuilder()
.UseStartup<ApiTestServerStartup>()
.UseEnvironment("TestInMemoryDb"));
}
public TestServer GetClientTestServerInstance()
{
return new TestServer(new WebHostBuilder()
.UseStartup<ClientTestServerStartup>()
.UseEnvironment("Development"));
}
[Test]
public async Task ShowProductsFromApiAtClientLevel()
{
using (var apiServer = GetApiTestServerInstance())
using (var clientServer = GetClientTestServerInstance())
{
var client = clientServer.CreateClient(apiServer);
var response = await client.GetAsync("/products"); // equivalent to: https://client-localhost:8080/products which relies on https://api-localhost:8081/products
var responseString = await response.Content.ReadAsStringAsync();
Assert.AreEqual("{ Shows product data coming from the api at client level }",
responseString);
}
}
}
Thanks to mjwills simple, but powerful question, I simply tested the code as it was and there were compile errors. But this got the stone rolling and I tried and failed until I figured it out.
What I basically did is inject the instantiated HttpClient of the ApiServer into my client app backend where an HttpRequest is made to the ApiServer. So whenever the client app wants to make an api call to the api server, it does so by using the injected HttpClient of the ApiServer.
Here is a snapshot of my Integration test and a little bit of my client app code that should anyone guide into the right direction:
// My abbreviated and redacted integration test using NUnit
[TestFixture]
public class IntegrationTestShould
{
public TestServer GetApiTestServerInstance()
{
return new TestServer(new WebHostBuilder()
.UseStartup<ApiTestServerStartup>()
.UseEnvironment("TestInMemoryDb"));
}
public TestServer GetClientTestServerInstance(TestServer apiTestServer)
{
// In order to get views rendered:
// 1. ContentRoot folder must be set when TestServer is built (or views are not found)
// 2. .csproj file of test project must be adjusted, see http://www.dotnetcurry.com/aspnet-core/1420/integration-testing-aspnet-core (or references for view rendering are missing)
var apiHttpClient = apiTestServer.CreateClient();
apiHttpClient.BaseAddress = new Uri(#"https://api-localhost:8081");
var currentDirectory =
Path.GetDirectoryName(Path.GetDirectoryName(TestContext.CurrentContext.TestDirectory));
var contentRoot = Path.GetFullPath(Path.Combine(currentDirectory, #"..\..\ProjectThatContainsViews"));
return new TestServer(new WebHostBuilder()
.UseStartup<ClientTestServerStartup>()
.UseContentRoot(contentRoot)
// register instantiated apiHttpClient in client app
.ConfigureServices(collection => collection.AddSingleton(apiHttpClient))
.UseEnvironment("ClientTestServer"));
}
[Test]
public async Task CorrectlyReturnProductsViewResult()
{
using (var apiServer = GetApiTestServerInstance())
using (var clientServer = GetClientTestServerInstance(apiServer))
{
var clientHttpClient = clientServer.CreateClient();
var response = await clientHttpClient.GetAsync("/products");
var responseString = await response.Content.ReadAsStringAsync();
response.EnsureSuccessStatusCode();
Assert.AreEqual("text/html; charset=utf-8",
response.Content.Headers.ContentType.ToString());
}
}
}
// My heavily abbreviated and redacted client app backend
public class HttpRequestBuilder
{
private readonly HttpClient _httpClient;
public HttpRequestBuilder(IServiceProvider serviceProvider)
{
// get instantiated apiHttpClient from client app dependency container (when running in test environment)
// or create new one (the case when running in environment other than test)
_httpClient = serviceProvider.GetService(typeof(HttpClient)) as HttpClient ?? new HttpClient();
}
public async Task<HttpResponseMessage> SendAsync()
{
// Setup request
var request = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri(#"https://api-localhost:8081/products")
};
// Send request
var result = await _httpClient.SendAsync(request);
// should have returned product data from api
var content = await result.Content.ReadAsStringAsync();
return result; // api product data processed further at client app level
}
}
I am building a system using Web API and Raven DB.
I am writing integration tests against the external boundary of this system.
public void GetAfterPostingPollReturnsPoll()
{
using (var client = HttpClientFactory.Create())
{
var poll = new
{
Question = "What is the answer?",
Options = new[] { "Yes", "No", "Maybe" }
};
var postResponse = client.PostAsJsonAsync("", poll).Result;
var pollLocation = postResponse.Headers.Location;
var getResponse = client.GetAsync(pollLocation).Result;
var actual = JsonConvert.DeserializeObject<Poll>(
getResponse.Content
.ReadAsStringAsync()
.Result);
Assert.Equal(poll.Question, actual.Question);
Assert.Equal(poll.Options, actual.Options);
}
}
When I submit an entry, the Controller interacts with a DocumentStore because that is how it works in production.
The trouble I am having is that the data produced in the test is never cleaned up.
Based on what I have been reading, I should use the EmbeddableDocumentStore for the purposes of my acceptance tests.
How might I use the DocumentStore normally but the EmbeddableDocumentStore when executing boundary tests like this one?
How do you "interact with DocumentStore" in your controller? The controller really only need to "interact" with the IDocumentSession that could be injected by the WebAPI infrastructure and in your integration test you register IDocumentStore to be implemented by EmbeddableDocumentStore (providing you use some kind of IoC container).
I am working on an asp.net mvc 3.0 application. In unit testing one of the action method in my controller, I was getting an error.
How to mock: Request.Params["FieldName"]
I have included Moq framework, but was not sure how to pass value
Here is my code... Please suggest...
var request = new Mock<System.Web.HttpRequestBase>();
request
.SetupGet(x => x.Headers)
.Returns(
new System.Net.WebHeaderCollection
{
{"X-Requested-With", "XMLHttpRequest"}
});
var context = new Mock<System.Web.HttpContextBase>();
context.SetupGet(x => x.Request).Returns(request.Object);
ValidCodeController target = new ValidCodeController();
target.ControllerContext =
new ControllerContext(context.Object, new RouteData(), target);
Params is a NameValueCollection property that can be set-up in a similar way to Headers:
var requestParams = new NameValueCollection
{
{ "FieldName", "value"}
};
request.SetupGet(x => x.Params).Returns(requestParams);
Another alternative to mocking the Context and all it's dependencies is to abstract the entire context/Params collection in a separate class, and mock that instead. In many cases this will make it easier, and avoids having to mock a complicated object graph:
Ex:
public void MainMethod()
{
var valueInQuestion = ISomeAbstraction.GetMyValue("FieldName");
}
You can now mock the GetMyValue method instead.
I am getting "Cannot access a closed Stream" when unit testing a Nancy web app.
My module is as follow:
public class MainModule : NancyModule
{
public MainModule()
{
Get["/{Name}"] = p =>
{
var command = this.Bind<MainCommand>();
return Response.AsJson(command.ExecuteGetMessage());
};
}
}
And my test is:
[Test]
public void Should_return_welcome_message()
{
// When
var bootstrapper = new DefaultNancyBootstrapper();
var browser = new Browser(bootstrapper);
BrowserResponse browserResponse = browser.Get("/", with =>
{
with.HttpRequest();
});
Console.WriteLine(browserResponse.StatusCode);
Console.WriteLine(browserResponse.Body.ToString());
// Then
Assert.AreEqual(HttpStatusCode.OK,browserResponse.StatusCode);
}
UPDATE: I am getting StatusCode = NotFound and the exception happens when trying to access browserResponse.Body.
I had a look at the Nancy forum and also here at StackOverflow.
I tried this solution: Nancy test doesn't find route in other assembly
but still not working.
When I run the test in debug mode I see that my module is been called but I still cant check the returned value.
What should I do in order to get it working?
Thanks
Ademar
You are getting a NotFound response because the route you have defined is different from the route you have called.
You are calling / in your test, but the module has a route of /{Name}.
The exception is because there is no body with a NotFound response.
Update your test to something like:
var bootstrapper = new ConfigurableBootstrapper(c=>c.Module<MainModule>());
var browser = new Browser(bootstrapper);
BrowserResponse browserResponse = browser.Get("/ademar", with =>
{
with.HttpRequest();
});
* Updated to include source from the comment *