Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Assert.SequenceEquals Not Working as Expected? #4385

Closed
simplesolutionssas opened this issue Sep 21, 2018 · 4 comments
Closed

Assert.SequenceEquals Not Working as Expected? #4385

simplesolutionssas opened this issue Sep 21, 2018 · 4 comments
Labels
feature-unit-testing support Whether you're using Rubberduck or you've forked it and have questions, never hesitate to ask!

Comments

@simplesolutionssas
Copy link

simplesolutionssas commented Sep 21, 2018

Hi Rubberduck team. I have this test case:

'@TestMethod
Public Sub Remainder() 
    On Error GoTo TestFail

    'Arrange:
    Dim Dividends As Variant
    Dividends = Array(1, 1, 5, 11, 10.2, 10.2, -1, -1, -5, -11, -10.2, -10.2)
    Dim Divisors As Variant
    Divisors = Array(1, 2, -2, 11, 0.5, -0.5, -1, -2, 2, -11, -0.5, 0.5)
    Dim ExpectedRemainders As Variant
    ExpectedRemainders = Array(0, 1, 1, 0, 0.2, 0.2, 0, -1, -1, 0, -0.2, -0.2)
        
    'Act:
    Dim Remainders(0 To 11) As Variant
    Dim Index As Long
    For Index = LBound(Dividends) To UBound(Dividends)
        Remainders(Index) = Arithmetic.Remainder(Dividends(Index), Divisors(Index))
    Next Index
       
    'Assert:
    For Index = LBound(Dividends) To UBound(Dividends)
        Assert.IsTrue ExpectedRemainders(Index) = Remainders(Index), "Values didn't match: " + CStr(ExpectedRemainders(Index)) + _
                                                                   " <> " + CStr(Remainders(Index))
    Next Index
    ' This should work, but isn't working currently.
    ' Assert.SequenceEquals ExpectedRemainders, Remainders, "Remainders are not as expected."

TestExit:
    Exit Sub
TestFail:
    Assert.Fail "Test raised an error: #" & Err.Number & " - " & Err.Description
End Sub

If I uncomment the Assert.SequenceEquals line (and comment the previous For block in the Assert section of the case), the test fails. But it passes if I run it as it's presented above.

Is this a bug? Am I missing something in the Arrange or Act sections? I tried looking at the documentation, but couldn't find anything useful to help me figure it out for myself.

Thanks!

Version 2.2.0.3806
OS: Microsoft Windows NT 10.0.17134.0, x64
Host Product: Microsoft Office x86
Host Version: 16.0.10730.20102
Host Executable: EXCEL.EXE

@retailcoder retailcoder added feature-unit-testing support Whether you're using Rubberduck or you've forked it and have questions, never hesitate to ask! labels Sep 21, 2018
@retailcoder
Copy link
Member

Assert calls document a reason for a test to fail - if a test doens't invoke any Assert, then that test will pass; that's by design, and consistent with the expectations of a unit test.

By default, the IAssert contract will be fulfilled by Rubberduck.AssertClass, which has rather stiff equality rules where mismatching types are considered to not be equal. Depending on the Variant subtypes involved, this may be what's happening here.

We have also implemented the IAssert interface with Rubberduck.PermissiveAssertClass, which attempts to mimick VBA's much more permissive equality rules (/implicit type conversions), but there are a number of known issues with it, including #4172. @IvenBach can you chime in with an updated status for PR #4170?

@retailcoder
Copy link
Member

Does this change anything (assuming the Remainder returns Double array items)?

Dim ExpectedRemainders As Variant
ExpectedRemainders = Array(CDbl(0), CDbl(1), CDbl(1), CDbl(0), CDbl(0.2), CDbl(0.2), CDbl(0), CDbl(-1), CDbl(-1), CDbl(0), CDbl(-0.2), CDbl(-0.2))

@retailcoder
Copy link
Member

retailcoder commented Sep 21, 2018

That test is essentially a "poor man's data-driven test" working around lack of data-driven support for Rubberduck unit tests (#1229).

An alternative work-around could be to split it into multiple tests that explicitly cover a single case, for example:

'@TestMethod
Public Sub GivenSameDividendAndDivisor_RemainderIsZero()
    Const value As Double = 10
    Const expected As Double = 0
    If value = 0 Then
        Assert.Inconclusive "Test is misconfigured"
        Exit Sub
    End If
    Dim actual As Double
    actual = Arithmetic.Remainder(value, value)
    Assert.AreEqual expected, actual
End Sub

'@TestMethod
Public Sub GivenNegativeDividendPositiveDivisor_RemainderIsNegative()
    Const dividend As Double = -5
    Const divisor As Double = 2
    If dividend >= 0 Or divisor <= 0 Then
        Assert.Inconclusive "Test is misconfigured"
        Exit Sub
    Else
        Dim actual As Double
        actual = Arithmetic.Remainder(dividend, divisor)
        Assert.IsTrue actual < 0
    End If
End Sub

'@TestMethod
Public Sub GivenPositiveDividendNegativeDivisor_RemainderIsPositive()
    Const dividend As Double = 5
    Const divisor As Double = -2
    If dividend <= 0 Or divisor >= 0 Then
        Assert.Inconclusive "Test is misconfigured"
        Exit Sub
    Else
        Dim actual As Double
        actual = Arithmetic.Remainder(dividend, divisor)
        Assert.IsTrue actual > 0
    End If
End Sub

'@TestMethod
Public Sub GivenNegativeDividendAndDivisor_RemainderIsNegative()
    Const dividend As Double = -5
    Const divisor As Double = -2
    If dividend >= 0 Or divisor >= 0 Then
        Assert.Inconclusive "Test is misconfigured"
        Exit Sub
    Else
        Dim actual As Double
        actual = Arithmetic.Remainder(dividend, divisor)
        Assert.IsTrue actual < 0
    End If
End Sub

'@TestMethod
Public Sub GivenZeroDivisor_ThrowsInvalidArgument()
    Const expectedError As Long = 5 'invalid procedure call or argument
    On Error GoTo TestFail
    Const dividend As Double = -5
    Const divisor As Double = 0
    If divisor <> 0 Then
        Assert.Inconclusive "Test is misconfigured"
        Exit Sub
    End If
    Dim actual As Double
    actual = Arithmetic.Remainder(dividend, divisor)
Assert:
    Assert.Fail "Expected error was not raised."
TestExit:
    Exit Sub
TestFail:
    If Err.Number = expectedError Then
        Resume TextExit
    Else
        Resume Assert
    End If
End Sub

@simplesolutionssas
Copy link
Author

simplesolutionssas commented Sep 21, 2018

I considered splitting the test in several smaller tests, but since this is a rather simple function in a rather extensive Arithmetic class, I decided to try and keep all test cases as compact as possible.

Anyway, this worked:

Dim ExpectedRemainders As Variant
ExpectedRemainders = Array(CDbl(0), CDbl(1), CDbl(1), CDbl(0), CDbl(0.2), CDbl(0.2), CDbl(0), CDbl(-1), CDbl(-1), CDbl(0), CDbl(-0.2), CDbl(-0.2))

Thanks Mathieu.

By the way, nice idea the one you have going on for supporting data-driven tests!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature-unit-testing support Whether you're using Rubberduck or you've forked it and have questions, never hesitate to ask!
Projects
None yet
Development

No branches or pull requests

2 participants