hhvm / hacktest

A unit testing framework for Hack
MIT License
29 stars 12 forks source link

Assertions #78

Closed azjezz closed 5 years ago

azjezz commented 5 years ago

example : sum.hack

function sum(int $a, int $b): int {
  $c = $a + $b;
  if ($c is int) {
    return $c;
  }

  throw new OverflowException();
}

MathFunctionsTest.hack

use namespace HH\Lib\Math;
use type Facebook\HackTest\HackTest;
use type Facebook\HackTest\DataProvider;
use type OverflowException;
use function sum;

class MathFunctionsTest extends HackTest {
  <<DataProvider('provideSumData')>>
  public function testSum(
    int $a, int $b, int $expected
  ): void {
    $this->assertEquals(sum($a, $b), $expected);
    $this->assertEquals(sum($b, $a), $expected);
  }

  public function provideSumData(): Container<(int, int, int)> {
    return vec[
      tuple(1, 2, 3),
      tuple(123, 123, 246)
    ];
  }

  public function testSumOverflow(): void {
    // if the exception was throw, call `addAssertionCount(1)`
    $this->setExpectedException(OverflowException::class);
    sum(Math\INT64_MAX, 1);
  }
}

expected output :

$ vendor/bin/hacktest test/MathFunctionsTest.hack
...
Summary: 3 test(s), 5 assertions, 3 passed, 0 failed, 0 skipped, 0 error(s).
azjezz commented 5 years ago

HackTest would have to override all methods of Assert in order to add assertion count ( and probably mark assert methods final ? )

class HackTest extends Assert {
  ...
  /**
   * Recursively sorts the two arbitrarily depth nested arrays and then checks
   * that the contents of the two arrays are equal.
   */
  <<__Override>>
  final public function assertKeyAndValueEquals<Tk as arraykey>(
    KeyedContainer<Tk, mixed> $expected,
    KeyedContainer<Tk, mixed> $actual,
    string $msg = '',
  ): void {
    parnet::assertKeyAndValueEquals($expected, $actual, $msg);
    $this->addAssertionCount(1);
  }
  ...
}
fredemmott commented 5 years ago

I think I remember discussing this elsewhere, but I can't find it; we definitely do not want to couple assertions to hacktest. fbexpect being a separate library is an intentional decision. While they're not entirely decoupled, we aim for it to be reasonably straightforward to use fbexpect from another testing framework, or to use another assertion library within hacktest, without there being a canonical one.

We also consider assertFoo() generally to be less clear than expect($a)->toFoo(), especially for error messages e.g. pytest assertEqual(a, b) is largely equivalent to assertEqual(b, a) in various language's *unit libraries