I treat assertion messages like comments: I try not to have them if I can avoid it, if I can make the intent clear from the code.

Usually this is an issue when there are several attributes you want to assert on that are related in some way. Extracting the assertions into a method named to indicate the aspect/relationship you're interested in makes it more obvious what is going on without the cost of maintaining the comment/message.

It really doesn't matter IMO, as long as the error message tells you what went wrong and where the problem is. Under normal operation, an assertion message will never be seen. If it is seen, there's a bug in the code somewhere, and you need to be able to track down and fix the bug.

The message should provide as much helpful information as possible - if you're checking that two values are equal and they're not, you should print out what the values are. That obviates the need to step into it with a debugger to examine the values. Of course, doing this requires that your language supports non-static information in assertion messages. If assertion messages can only be fixed, static strings, you can't add extra runtime information without jumping through hoops.

Roddy's suggestion is a good one--it certainly makes the "cost" of adding new assertions much cheaper (i.e. doesn't require thinking of or typing out a new string message). Believe it or not, but implementing his suggestion has had a significant impact on my usage of assertions.

If you're still looking for a clearer text message, though, you might consider something like:

"Expected 4-2 to equal 2"

This seems to make clear (at least to me) that the expected answer was 2, but that the expectation was not met...