Hi Gerard,
Replies inline...
On Fri, Feb 3, 2017 at 10:25 PM, Gerard Meszaros <
gmka...@gmail.com> wrote:
>
>
> On Friday, February 3, 2017 at 12:07:53 PM UTC-7, charlie wrote:
>>
>> Hi Gerard,
>>
>> This __has__ changed and more change is likely in the future.
>>
>> To put it in perspective, the use of an AssertionException to communicate
>> failure is an implementation detail.
>
>
> I think this is a debatable point. This is externally visible behaviour.
> That isn't an "implementation detail".
I think we have a fundamental disagreement about the difference
between interface and implementation. Like any software, NUnit
guarantees certain behaviors, but it has many more "observable
behaviors". If anything that is observed is viewed as an unchangeable
part of the interface, then it becomes virtually impossible to change
anything. We - like other software - try to push back against that
tendency by clearly telling people what is guaranteed and what is not.
Of course, if enough people start to rely on something being
implemented in a certain way, you can end up being forced to maintain
it in the future. It's a sort of retroactive feature creep.
Fortunately, I don't think that's the case here, since the impact is
fairly limited.
>> However, it has been in use for so long that many people came to rely on
>> it.
>
>
> In every member of the xUnit family that i have ever used since VbUnit,
> this was the behaviour. No side-effects. So if you want to check that a
> Custom Assertion fails when it should, you simply call the assertion inside
> a TryCatch block (or an Assert.Throws. ) And the result of the test is
> entirely up to you. There are no "hidden side effects". Changing this is a
> BIG DEAL.
I"m sure you aren't trying to say that NUnit is required to work
internally the same as VbUnit, et al. I realize that the difference
could be confusing for someone trying todo similar things in multiple
frameworks, but I don't think that's the case for most users.
Reporting the result of a failure isn't a side effect. It is the
effect of any assertion. In fact, I could just as well call the
throwing of an exception the side effect. The object of running a test
is to return a result after all, not to throw an exception.
>> The immediate cause of this change is the introduction of warning results
>> and multiple assertion failures per test.
>
>
> When was this breaking change introduced? I trolled through the list of
> breaking changes and didn't see it.
It was in 3.6, released a few weeks ago. I didn't put it in the
breaking changes page because I actually wasn't thinking of it as a
breaking change but as a change to an implementation detail. However,
since it can break some existing tests, I should add it there.
Well, you're a user and I just told you how to use it, so... yes!
The Internal namespace exists to tell people that they are using part
of the NUnit implementation, without actually declaring the class as
internal and making it inaccessible to them. People writing
extensions, for example, need to use Types in that namespace.
>>
>>
>> TestExecutionContext is in the NUnit.Framework.Internal namespace. I gave
>> some thought to exposing this as a feature in TestContext, but I really
>> couldn't think of a use case to justify it. If you know of one that's not
>> about testing NUnit, we could do something like
>>
>> Assert.Isolated(() =>
>> {
>> // your code
>> });
>>
>> Alternatively, we could expose something similar in TestContext.
>
>
> Both of these are ugly solutions to a self-imposed problem. It changes
> something that was trivially easy to test into something that is hard to
> test. (Assertions were easy to test because they had no side effects.)
With respect, I think you are focused so much on the problem you are
trying to solve - which is not a common problem for general users -
that you are n
ot paying attention to why it was necessary to do this in the first place.
In C#, there is no ready way to throw an exception and then resume the
same code. That's what would be necessary in order to allow multiple
assertions to be reported using exceptions.
As I explained, the above was a possible way to expose this feature,
which I did not implement. I don't like it either. I'd be happy to
have a suggestion, if you can put yourself in the mood to offer
something positive.
> Testing custom assertions is the use case. It has nothing to do with testing
> NUnit itself so it should not have to rely on "internal" features.It as
> about writing clean tests by building up a DSL of custom assertions that use
> domain-specific language to express the expectations. (They don't even need
> to be called "assertions" but they do need to throw AssertionException to
> fail the test and typically do so by calling framework-provided assertions.)
> Having to create isolated TestContexts to test a CustomAssertion is relying
> on "implementation details".
Personally, I don't think it is possible to write custom assertions
without relying on implementation details. Someone extending the
framework has to understand internals except for the simplest cases.
When you use a try / catch to test, you are using an internal
implementation detail. I've been telling people that for years in our
forums. It's the main reason that user code should not attempt to
catch any exceptions except the ones the tests or the system under
test is known to throw. I've often told people "the next version of
NUnit may not throw an exception." Well, now it has happened!
> Personally, I think think this is a bad design. One that is right up there
> with the sharing of the testcase instance among test methods.This will be a
> stumbling block for people upgrading from earlier versions of NUnit. And it
> moves NUnit farther and farther from the common feature set of the xUnit
> family. Pretty soon it will be just as far out as TestNG, the "bastard
> child" of the family.
>
> At least make the default behaviour the same as before and force users to
> enable the new multiple-failure behaviour. Please!
We'll ignore the insults to the design and take the suggestion into
account. Frankly, I haven't seen the problems you predict so far. One
user with a very obscure use of DelayedConstraint in combination with
Throws.Nothing ran into a problem that forced the use of the isolated
context.
As far as requiring a switch to enable the full features of NUnit,
that seems like a non-starter to me. Most users just want to run tests
and see the results. It's hard to explain why we have added new
features but required them to turn the feature on at the command-line
before they can use it.
Frankly, your use case is that you would prefer NUnit to work alike
with some competing frameworks in order to make it easier to create
training. That's not a terribly convincing case. NUnit is different
software. It has different features and that's part of what makes this
an interesting space.
OTOH, the use case of someone trying to test custom assertions is a
good one. It's precisely the reason we have the isolated context, in
fact. The logic is: I need a separate context to run this test because
the test result is in the context. I want tp examine the result in
that isolated context, not the result of the test itself - the one I'm
running. Unfortunately, I just don't have a good syntax right now to
expose it to users.
>>
>>
>> Hope this is helpful!
>
>
> It has been very helpful in confirming I wasn't going crazy! The last time I
> was this confused by any member of the xUnit family was when I tried to
> implement Lazy Setup in NUnit 2.0 and it didn't work. I spent hours in the
> debugger before convincing myself that I was doing things right and it was
> the framework that was leaking information between test methods. (I can't
> remember; has this been fixed in NUnit 3? Last I heard you were concern
> about breaking legacy tests that depended on it. ;-) )
Sorry, I don't know (or remember) what that's about. Did you file an
issue on it? Of course, we don't work on the V2 code base any longer,
but I believe we migrated all the issues that would still apply.
In any case, I don't undersrtand why you would want to implement Lazy
Setup for NUnit at all, since we have OneTimeSetUp for (shared)
fixtures.
> So what can I do right now to let me test my Custom Assertions. I teach this
> stuff to people in every course I run and I need to be able to tell them how
> to do it in NUnit 3.x; it wouldn't look very good to have NUnit 3 be the
> only member of the family in which we cannot test our Custom Assertions. (I
> already have to explain some of the other "foibles" of NUnit; I'd like the
> list of exceptions to get smaller, not larger!) I'm embarrassed to say that
> I'm still teaching based on NUnit 2.x (and running my exercises in 2.2.8)
> because of the inability to (meta)test my tests due to the changes in the
> framework after 2.2.8.
Well, as I'm sure you know, NUNit 2.2.8 was released in 2007. It's now
2017. That's a lot of change to swallow all at once!
It's clearly not impossible to (meta)test NUnit assertions after 2007,
since we've continued to do it all along. Feel free to ask for help
but asking us to not progress doesn't cut it.
My own approach would be to establish an isolated context (using the
ugly syntax or some new cleaner one we may subsequently invent) and
return the result of the assertion from it. Examine the fields of the
result to see if they are as you would expect. IMO, this is much
cleaner than catching an exception, especially since the exception has
much less information in it than the result. Of course, to do this,
you are looking at NUnit internals, but the exception is an internal
detail as well.
If you can get past the simple fact that NUnit does not include in
it's design goals "Use an implementation like what has been used since
vbUnit" then I'm happy to help you figure out how to test your stuff.
Charlie