The idea is this: There are certain requirements on a data contract; like it being serializable and whatnot.
To verify this automagically the test program must be able to find them. It can be done through: 1) they are all in the same namespace. 2) their names are all suffixed with “DataContract” 3) they all implement “IDataContract”
Then through reflection/RTTI a test can get all data contracts and verify they are all ok.
Unfortunately Aspnet does not have a way to verify that an endpoint returns a data contract through unit testing; it has to be solved through integration testing or surveillance of production.
var serviceProvider = new ServiceCollection().AddHttpClient().BuildServiceProvider();
var httpClientFactory = serviceProvider.GetService<IHttpClientFactory>();
I added some health check to my aspnet site to trigger from Kubernetes startupProbe and sometimes got
{
"EventId": 1,
"LogLevel": "Error",
"Category": "Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware",
"Message": "An unhandled exception has occurred while executing the request.",
"Exception": "System.Threading.Tasks.TaskCanceledException: A task was canceled.
at Microsoft.Extensions.Diagnostics.HealthChecks.DefaultHealthCheckService.CheckHealthAsync(Func`2 predicate, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Diagnostics.HealthChecks.HealthCheckMiddleware.InvokeAsync(HttpContext httpContext)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task)",
"State": {
"Message": "An unhandled exception has occurred while executing the request.",
"{OriginalFormat}": "An unhandled exception has occurred while executing the request."
}
}
There is nothing in my health checking code that can throw (famous last words…). In the stack above there is none of my code.
To make a long story short I moved the calls to UseHealthCheck from below UseEndpoints to above UseAuthentication as my endpoints are anonymous (they are very lightweight).
In a (unit) test I sometimes add extra tests to check the test tests what is anticipated.
user = new User(Id="A", Name = "N1")
sut.Create(user)
saved = sut.Get("A")
saved.Name.Should.Be("N1", "Sanity check we know what we have stored.")
// Act.
sut.Clear("A")
// Assert.
result = sut.Get("A")
result.Name.Should.Be(null)
Notice the “sanity check” to verify a bug didn’t set Name to null when creating the user.
My naming convention is “Sanity check” or “Nykterhetskontroll” in Swedish. [I know the translation, word per word, is incorrect.]
I updated some references in my Azure Devops build and got the following error in the unit testing task:
...
##[error]Error: The process '/opt/hostedtoolcache/dotnet/dotnet' failed with exit code 1
Result Attachments will be stored in LogStore
Run Attachments will be stored in LogStore
No Result Found to Publish '/home/vsts/work/_temp/_fv-az101-233_2021-09-09_10_21_12.trx'.
No Result Found to Publish '/home/vsts/work/_temp/_fv-az101-233_2021-09-09_10_21_17.trx'.
No Result Found to Publish '/home/vsts/work/_temp/_fv-az101-233_2021-09-09_10_21_24.trx'.
##[warning].NET 5 has some compatibility issues with older Nuget versions(<=5.7), so if you are using an older Nuget version(and not dotnet cli) to restore, then the dotnet cli commands (e.g. dotnet build) which rely on such restored packages might fail. To mitigate such error, you can either: (1) - Use dotnet cli to restore, (2) - Use Nuget version 5.8 to restore, (3) - Use global.json using an older sdk version(<=3) to build
Info: Azure Pipelines hosted agents have been updated and now contain .Net 5.x SDK/Runtime along with the older .Net Core version which are currently lts. Unless you have locked down a SDK version for your project(s), 5.x SDK might be picked up which might have breaking behavior as compared to previous versions. You can learn more about the breaking changes here: https://docs.microsoft.com/en-us/dotnet/core/tools/ and https://docs.microsoft.com/en-us/dotnet/core/compatibility/ . To learn about more such changes and troubleshoot, refer here: https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/build/dotnet-core-cli?view=azure-devops#troubleshooting
##[error]Dotnet command failed with non-zero exit code on the following projects :
Async Command Start:
Publish test results Publishing test results to test run '1136330'.
...
Especially the last, “Dotnet command failed … on the following projects” does not give the clue I am looking for. What failed?
To cut a long story short: One of my test project lacked reference to Microsoft.NET.Test.Sdk.
A longer story is that I updated from xunit.runner.visualstudio from 2.4.1 to 2.4.3 and it doesn’t have a reference to the Microsoft.Net.Test.Sdk project as it is no longer Visual studio that holds the reference but the project itself. The clues I got were from https://github.com/xunit/visualstudio.xunit/issues/219 and https://github.com/xunit/visualstudio.xunit/issues/259 in no special order.
IIRC the most usual, unwanted, exception we get is null reference error. The second is off-by-one error.
The off-by-one error is the result of us programmers on remembering to subtract one from an index, or subtracting once too many.
Alas we should have 1 based index, like natural language, and let the computer do the subtraction.
What…? That is not how computers work!
No.
But that is how Humans work.
It is many years since we stopped arguing that a computer wants its data layed out such and therefore we adopt to it. Today we try to solve business problems, not computer problems (your domain may vary). We use higher level language. We name our variables after the domain. We use domain language.
We do not ask the customer for the zeroth invoice. And when we ask for the 2nd invoice we expect the 2nd invoice in a list.
The reason for 0 based index is, I believe, a historical technical reason.
When programming assembler, it is easy to point to a memory position and then add an index. Hence having a zero based index is a natural thing; we solve a computer problem. Then C, a higher level language, comes along. It is way above assembler but is till constructed to be close to the physical machine to be easy to implement on any processor. By that time we still solved computer problems and keeping a zero based index was probably a no brainer.
Then came Java and C#. They try to look like C/C++ due to reasons of not-thinking-things-through and it-is-easier-to-not-move-the-cheese. They keep the zero based index even though they didn’t have to. So now we are stuck with it.
Until either 1) we invent a new operator
1
myArray@1
or
1
myArray/1/
or 2) invent a yet new language.
Until then: Keep spreading the word that we should have a 1 based index.
It is a good custom to write out Act and Assert in test as it helps to write the test in a clean way; and helps the next reader to understand where Arrange stops and Act begins. It helps the writer to not involuntarily write Act statements in Assert. Like so:
myTest() sut = setup()
// Act. sut.do()
// Assert. assert(sut.value).equals(12)
The above code is too simple to make the upside of this coding standard visible but soon tests get a few lines long and commentning Act and Assert is a good idea.
I don’t bother to write out // Arrange any more as all tests start with Arrange anyway.
Well… that was not true. I have stumbled upon tests with several Arrange, Act and Assert in them. Typically for integration tests.