Personally I would spit out an output log as well as the general test value. Then you can see the failure and go check the log. You can clear the log each time you run the test. Remember it's a unit test framework, not a test automation framework. Unit tests usually are very specific and not running tons of assertions all at once. The goal would be 1 assertion per unit test or only grouped assertions if any of them cause the failure of a specific function.
You could throw a custom message for each one as you mention if you like, but if you spit a standard log function out for each step and append the file it with specific data from each assertion, you can include the content of the assertion to get each failure of step and just look at the log when you need to.
like call the log to append a line and include text like "[unit test name]_Assertion: [variable.tostring()]" with the variable being what it is you were trying to assert against. Literally spit out the text, it should mean something to you with the unit test name reference in front of it so you can see if 30 assertions exist and 3 fail you should get an idea of which ones from that.
Replace the standard assert function with your custom one that logs and then returns the true/false value so it works the same for every assertion. Naturally you would need to write your own assert class that ties back into the framework though.
Ask this on regular Stack Overflow as this is now a dev question based on comments:
How do I customize NUnit in order to write my own Assert class method that has more information in it and then tie that back into the existing NUnit framework?
Has anyone done this before and can anyone post examples to help me get started on this?
P.S. Search on there first as that may already be there in various format as some of the questions overlap. You can then delete this question from here as it's now "off-topic".