Test all properties with single test function
too vague &amp; hiding test cases


[DataRow("Name", "A normal name", "A normal name", new string[] { "Name" })]
[DataRow("Name", null, null, new string[] { "Name" })]
[DataRow("Name", "", "", new string[] { "Name" })]
[DataRow("Name", "A normal name", "A normal name", new string[] { "Name" })]
[DataRow("Name", "A really very super duper long string to test the overall allowed length", "A really very super duper long string to test the overall allowed length", new string[] { "Name" })]



Tests should be testing very specific things. This test however isn't doing that. I looks like it's not simply testing the PropertyChanged event. If it was, then a single DataRow would be enough to tell whether the event fires or not.

It seems to also test some conditions that might prevent it from firering. Such tests should be done separately because here it's not clear what conditions you are testing. 



too many hardcoded strings

Technically I find it's ok but to my taste there are too many hardcoded strings. I wouldn't say anything if it was just data but since they are property names I don't like them being strings.

You could use nameof to replace them with something more dynamic but then the test would not be very readable anymore.



extend Assert &amp; use expressions

Instead it'd be a better idea to write an extension for the Assert.That property that you could use for testing the event in this way:

Assert.That.PropertyChanged(
    new Customer(), 
    x =&gt; x.FirstName = "John", 
    x =&gt; x.FirstName,
    x =&gt; x.FullName
);


where the signature of the method is:

public static void PropertyChanged&lt;T&gt;(
    this Assert assert, 
    T obj, 
    Action&lt;T&gt; setProperty,
    params Expression&lt;Func&lt;T&gt;&gt;[] changedProperties
)
{
    ...
}


now you can do the reflection magic here.



This is just an idea but you could of course have a couple of such extensions. One very gneric and another one that e.g. assumes that the property being set always fires an event for it.



confusing naming


foreach (var s in propChangedNames)



If you must give variables single letter names then let them at least be derived from the main name. Here p or pcn would be appropriate. s does not stand for anything. The only exception is x in lambda expressions which stands for current-item.



misses the point


  although it could even be generalized with a templated method for all classes


Then do this because otherwise you failed to reach the third goal which is:


  Don't write a ton of very repetitive test code