0

This ought to be possible - and I think it might be possible somehow using Constraints, but they seem to only take one variable as input, which fails.

Here's the simplest example I've run into:

  1. I have an object with size (i.e. a 2D variable)
  2. I need to show it's partly off-screen
  3. This happens if x is outside a range OR y is outside a range
  4. ... I can't see how to achieve that in NUnit (without throwing away critical info)

It seems that NUnit fundamentally doesn't support anything other than 1-dimensional problems, which would be absurd, so I must be missing something here. But the only methods I can find all only work with 1-d inputs.

Things I've thought of ... but don't work:

i. Assert.True( A | B ) - useless: it throws away all the "expected" info and generates such weak messages that there's essentially no point using a testing framework here

ii. Assert.Or - doesn't allow multiple variables, so you can test "X is 3, or 4, or 5", but you cannot test "X is 3, or Y is 4"

iii. Writing custom assertions for a Tuple<A,B> - but then it goes horribly wrong when you get to "greater than" ... is "<A,B> greater than <C,D>" is a non-trivial question and ends up with code that's vastly confusing and I can guarantee someone will misunerstand and misapply it in future (probably me :))

9
  • Please, share some code example with problem, that you've faced. Others can use to help you. Currently it's hard to understand, what is your problem about Commented May 16, 2020 at 20:23
  • The formatting was mangled, but I've corrected it. If there's something specific that's not clear please highlight it Commented May 16, 2020 at 20:24
  • Please, share arrange and act steps of your test Commented May 16, 2020 at 20:28
  • Why? That has literally nothing to do with the problem. If I could write the test, I wouldn't need to ask. The problem is literally: how do you even write such a test? Commented May 16, 2020 at 20:29
  • I agree with the final part of Charlie's answer, that a custom constraint is the best solution here. NUnit constraints have a single "actual" value. In this case, your "actual value" is your "object with size", which I presume there isn't a built in constraint specifically to handle. In which case, your solutions are either to do what you've suggested in (i) (which I agree, isn't great!), or right a custom constraint specific to the type of your "object with size". See hermit.no/how-to-extend-the-nunit-constraints for a good How-To... Commented May 17, 2020 at 1:51

2 Answers 2

3

To be honest, you haven't done a great job of explaining what you want. I re-read several times and I think I have guessed right, but I shouldn't have to so please try code for the next problem.

I take it that you wish it were possible to change the actual value in the course of an NUnit constraint expression... something like this...

// NOT WORKING CODE Assert.That(X, Is.OnScreen.And.That(Y, Is.OnScreen)); 

(Where "OnScreen" makes the test you need)

But you can't do that. To work within the existing features of NUnit, each Assertion needs to deal with one actual value.

Simplest thing I can think of is to use multiple assertions:

Assert.Multiple(() => { Assert.That(X.IsOnScreen); Assert.That(Y.IsOnScreen); }); 

I say this is simple because NUnit already does it. It's not very expressive, however.

If you are doing a lot of such tests, the simplest thing is to create a custom constraint, which deals with your objects as an entity. Then you would be able to write something like

Assert.That(myObject, Is.OnScreen); 

Not just as pseudo-code, but as actual code. Basically, you would be creating a set of tests on rectangles, representing the object bounds on the one hand and the screen dimensions on the other.

Sign up to request clarification or add additional context in comments.

2 Comments

NUnit Multiple assertions - according to the docs - is the same as an AND constraint, except less effective (it executes identically, it just doesn't terminate immediately. But the end result is the same). It is not an OR constraint.
It looks to me like a Custom Constraint should be able to handle this, although the my first attempt at design/implementation is proving very convoluted, simply to workaround the lack of Tuple-compatible calls in the framework. This still feels like it must be wrong, it's so over-complicated :).
1

1-dimensional problems

To be frank I don't really get it. If you think of it, actually all members in Assert are tools for boolean problems (zero dimension). Which perfectly makes sense for raising a red or green flag in case of all assertions.

Your problem is also a yes/no question: "Is my object off-screen?".

i. Assert.True( A | B ) - useless: it throws away all the "expected" info and generates such weak messages

Nothing stops you to specify the message, which is displayed if the assertion fails:

Assert.IsTrue(myObject.IsOnScreen(), $"Object is off-screen: {myObject.Bounds}") 

But in this particular case you can easily turn it into an equality assertion:

// here also the default message may be clear enough Assert.AreEqual(expected: screenBounds, actual: screenBounds.UnionWith(myObject.Bounds)); 

And voila, multiple (four) properties were compared at once...

3 Comments

Your "Bounds" approach is a great one, I like it. Unfortunately I'm not using windows forms, so I don't have that class, but in theory it's probably the most correct solution for this case.
Re: your "nothing stops you to specify the message", you still haven't included the expected-vs actual, which requires writing out a much more complicated message. At which point: why are we even using a test framework? This is exactly what it's supposed to be doing for us :)
What I meant by 2D vs 1D compare ... "all members in Assert are tools for boolean problems" - methods that take a pair of basic datatypes (e.g. float, or e.g int) ... an "expected" and an "actual" ... are doing a 1dimensional compare: they check a single value of a single variable. A Bounds object varies in two dimensions: X and Y ... and often it only makes sense to compare BOTH those dimensions simultaneously.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.