1

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.

Stefan0309
  • 1,602
  • 5
  • 23
  • 61
  • Consider to use [FluentAssertions](https://fluentassertions.com/) library which provide nice(fluent) api for asserting actual data with expectations. In your case it would be simply `responseObject.Should().BeEquivalentTo(expected)` – Fabio Jan 22 '19 at 00:36

2 Answers2

2

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
tobypls
  • 839
  • 1
  • 8
  • 21
  • Yes, I understand it. And which is better? Functional test or integration test? And how I can test when I pass some object as argument? For example how can I test a method called SaveCBO(AP_CBO entity) which will calls the database and actually save it? For example, in integration test? Then I will use PostAsync(url, body)? – Stefan0309 Jan 21 '19 at 11:47
  • Alot of questions in one comment. The choice of testing strategy is basically up to you. Some times, when my controller action doesn't contain alot of business logic I think that integration tests are sufficient. However, if there's alot going on in your method, I would recommend writing Unit tests to verify the expected behavour and maybe add some integration tests to verify that the action is actually callable. – tobypls Jan 21 '19 at 11:50
  • As for how to pass an object as an argument, you just add a body to the request as you would regularily do in ASP.Net Core. In Unit tests you would only call the method with an object. – tobypls Jan 21 '19 at 11:53
  • I am trying to get it work, writing the JsonConvert lib (second option), but I am getting failed test and error: `Message: The following constructor parameters did not have matching fixture data: WebApplicationFactory`1 factory `. I can;t figure it out this error. I really just copied your example. – Stefan0309 Jan 21 '19 at 14:53
  • What line causes this exception? Are you able to execute the test successfully without my added lines? (`var content = await httpResponseMessage.Content.ReadAsStringAsync(); var serviceDto = JsonConvert.DeserializeObject>(content);`) – tobypls Jan 21 '19 at 15:03
  • Nope..I just added some dummy method like `public string TestMethod(){return "Test";}` and when I call it, the same error appears. I think that I am not able to do it like this..Btw - my debug tests don't work. My debugger never get hit. – Stefan0309 Jan 21 '19 at 15:12
  • Seems like you need to set some stuff up to be able to run your tests. Have a look at https://stackoverflow.com/questions/51155987/the-following-constructor-parameters-did-not-have-matching-fixture-data and https://learn.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-2.2#basic-tests-with-the-default-webapplicationfactory EDIT: I saw that you wrote this in your question: "I tested some "light" methods such as if service method returns SucessCode and it works". Are you able to revert your code to that state and test with the lines that i provided? – tobypls Jan 21 '19 at 15:22
  • thanks for the links. That "light" methods are in WebProject, and tests for them is simple, just calling their Startup.cs as _factory, and then calling GetAsync method. However, those methods that I have problem are Service methods and have some DI in Startup class. It seems to me as if I didn't run the service in localhost.. – Stefan0309 Jan 21 '19 at 15:29
  • Now I realized that I have authorization for my service methods, maybe I need to provide some mock for those? – Stefan0309 Jan 21 '19 at 15:39
  • Seems like you either have to mock your DI dependencies and authentication (using Moq or something like that) and inject your dependencies from the test into your StartUp (code depends on your DI framework). One guide that might help you: https://automationrhapsody.com/net-core-integration-testing-mock-dependencies/ – tobypls Jan 21 '19 at 15:42
0

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

nzrytmn
  • 6,193
  • 1
  • 41
  • 38