diff --git a/composer.json b/composer.json
index eea4bcb..6407c9c 100644
--- a/composer.json
+++ b/composer.json
@@ -30,6 +30,13 @@
         "wiz-develop/php-cs-fixer-config": "^8.3",
         "phpstan/phpstan": "^1.12",
         "phpunit/php-code-coverage": "^11.0",
-        "phpunit/phpunit": "^11.3"
+        "phpunit/phpunit": "^11.3",
+        "phpstan/extension-installer": "^1.4",
+        "phpstan/phpstan-strict-rules": "^1.6"
+    },
+    "config": {
+        "allow-plugins": {
+            "phpstan/extension-installer": true
+        }
     }
-}
\ No newline at end of file
+}
diff --git a/composer.lock b/composer.lock
index 9bb7c57..4d6c792 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "1d15f7c07e1b7c6eea1e820050a7f08d",
+    "content-hash": "c783ccd266bcfdefe449f2944d204246",
     "packages": [],
     "packages-dev": [
         {
@@ -744,6 +744,54 @@
             },
             "time": "2022-02-21T01:04:05+00:00"
         },
+        {
+            "name": "phpstan/extension-installer",
+            "version": "1.4.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/phpstan/extension-installer.git",
+                "reference": "85e90b3942d06b2326fba0403ec24fe912372936"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/phpstan/extension-installer/zipball/85e90b3942d06b2326fba0403ec24fe912372936",
+                "reference": "85e90b3942d06b2326fba0403ec24fe912372936",
+                "shasum": ""
+            },
+            "require": {
+                "composer-plugin-api": "^2.0",
+                "php": "^7.2 || ^8.0",
+                "phpstan/phpstan": "^1.9.0 || ^2.0"
+            },
+            "require-dev": {
+                "composer/composer": "^2.0",
+                "php-parallel-lint/php-parallel-lint": "^1.2.0",
+                "phpstan/phpstan-strict-rules": "^0.11 || ^0.12 || ^1.0"
+            },
+            "type": "composer-plugin",
+            "extra": {
+                "class": "PHPStan\\ExtensionInstaller\\Plugin"
+            },
+            "autoload": {
+                "psr-4": {
+                    "PHPStan\\ExtensionInstaller\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "description": "Composer plugin for automatic installation of PHPStan extensions",
+            "keywords": [
+                "dev",
+                "static analysis"
+            ],
+            "support": {
+                "issues": "https://github.com/phpstan/extension-installer/issues",
+                "source": "https://github.com/phpstan/extension-installer/tree/1.4.3"
+            },
+            "time": "2024-09-04T20:21:43+00:00"
+        },
         {
             "name": "phpstan/phpstan",
             "version": "1.12.3",
@@ -802,6 +850,55 @@
             ],
             "time": "2024-09-09T08:10:35+00:00"
         },
+        {
+            "name": "phpstan/phpstan-strict-rules",
+            "version": "1.6.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/phpstan/phpstan-strict-rules.git",
+                "reference": "363f921dd8441777d4fc137deb99beb486c77df1"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/363f921dd8441777d4fc137deb99beb486c77df1",
+                "reference": "363f921dd8441777d4fc137deb99beb486c77df1",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.2 || ^8.0",
+                "phpstan/phpstan": "^1.11"
+            },
+            "require-dev": {
+                "nikic/php-parser": "^4.13.0",
+                "php-parallel-lint/php-parallel-lint": "^1.2",
+                "phpstan/phpstan-deprecation-rules": "^1.1",
+                "phpstan/phpstan-phpunit": "^1.0",
+                "phpunit/phpunit": "^9.5"
+            },
+            "type": "phpstan-extension",
+            "extra": {
+                "phpstan": {
+                    "includes": [
+                        "rules.neon"
+                    ]
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "PHPStan\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "description": "Extra strict and opinionated rules for PHPStan",
+            "support": {
+                "issues": "https://github.com/phpstan/phpstan-strict-rules/issues",
+                "source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.6.0"
+            },
+            "time": "2024-04-20T06:37:51+00:00"
+        },
         {
             "name": "phpunit/php-code-coverage",
             "version": "11.0.6",
@@ -4205,12 +4302,12 @@
     ],
     "aliases": [],
     "minimum-stability": "stable",
-    "stability-flags": [],
+    "stability-flags": {},
     "prefer-stable": false,
     "prefer-lowest": false,
     "platform": {
         "php": ">=8.3"
     },
-    "platform-dev": [],
+    "platform-dev": {},
     "plugin-api-version": "2.6.0"
 }
diff --git a/phpstan.neon.dist b/phpstan.neon.dist
index 753f54a..7f229a6 100644
--- a/phpstan.neon.dist
+++ b/phpstan.neon.dist
@@ -4,5 +4,6 @@ parameters:
     level: max
     paths:
         - src
+        - tests
     typeAliases:
         BasicTypes: 'int|string|bool|null|float|array|iterable|callable|resource|object'
diff --git a/src/Option.php b/src/Option.php
index 61365b8..68047b1 100644
--- a/src/Option.php
+++ b/src/Option.php
@@ -103,7 +103,7 @@ public function and(self $right): self;
      * @param  Closure(T): Option<U> $right
      * @return Option<U>
      */
-    public function andThen(Closure $right): self;
+    public function andThen(Closure $right): self; /** @phpstan-ignore method.childParameterType */
 
     /**
      * @see https://doc.rust-lang.org/std/option/enum.Option.html#method.or
diff --git a/src/Option/None.php b/src/Option/None.php
index ac8425c..7780f5f 100644
--- a/src/Option/None.php
+++ b/src/Option/None.php
@@ -33,6 +33,9 @@ public static function unit(mixed $value): self
     /**
      * @return $this
      */
+    /**
+     * @phpstan-ignore method.childParameterType
+     */
     #[Override]
     public function andThen(Closure $right): self
     {
diff --git a/src/Option/Some.php b/src/Option/Some.php
index 94b12fa..4170dcc 100644
--- a/src/Option/Some.php
+++ b/src/Option/Some.php
@@ -41,6 +41,9 @@ public static function unit(mixed $value): self
      * @param  Closure(T): Option<U> $right
      * @return Option<U>
      */
+    /**
+     * @phpstan-ignore method.childParameterType
+     */
     #[Override]
     public function andThen(Closure $right): Option
     {
diff --git a/src/Result.php b/src/Result.php
index 886452b..0cf5999 100644
--- a/src/Result.php
+++ b/src/Result.php
@@ -117,7 +117,7 @@ public function and(self $right): self;
      * @param  Closure(T): Result<U, F>                          $right
      * @return (F is BasicTypes ? Result<U, E|F> : Result<U, E>)
      */
-    public function andThen(Closure $right): self;
+    public function andThen(Closure $right): self; /** @phpstan-ignore method.childParameterType */
 
     /**
      * @see https://doc.rust-lang.org/std/result/enum.Result.html#method.or
diff --git a/src/Result/Err.php b/src/Result/Err.php
index d578c4d..35bed4a 100644
--- a/src/Result/Err.php
+++ b/src/Result/Err.php
@@ -42,7 +42,7 @@ public static function unit(mixed $value): self
     }
 
     /**
-     * @return $this
+     * @phpstan-ignore method.childParameterType, missingType.generics
      */
     #[Override]
     public function andThen(Closure $right): self
diff --git a/src/Result/Ok.php b/src/Result/Ok.php
index edc38f1..fd3ff57 100644
--- a/src/Result/Ok.php
+++ b/src/Result/Ok.php
@@ -46,9 +46,13 @@ public static function unit(mixed $value): self
      * @param  Closure(T) :Result<U, F> $right
      * @return Result<U, F>
      */
+    /**
+     * @phpstan-ignore method.childParameterType
+     */
     #[Override]
     public function andThen(Closure $right): Result
     {
+        // @phpstan-ignore return.type
         return $right($this->value);
     }
 
diff --git a/src/Result/functions.php b/src/Result/functions.php
index 9ac05e0..a2b4e18 100644
--- a/src/Result/functions.php
+++ b/src/Result/functions.php
@@ -92,15 +92,18 @@ function transpose(Result $result): Option
 }
 
 /**
- * @return Result<bool, non-empty-list<mixed>>
+ * @template T
+ * @template E
+ * @param  (Result<T, E>|Result)           ...$results
+ * @return Result<bool, non-empty-list<E>>
  */
-/** @phpstan-ignore-next-line */
-function combine(Result ...$results): Result
+function combine(Result ...$results): Result // @phpstan-ignore-line
 {
     $errs = array_filter($results, static fn (Result $result) => $result->isErr());
     if (count($errs) > 0) {
+        // @phpstan-ignore return.type
         return Result\err(array_values(array_map(static fn (Result $result) => $result->unwrapErr(), $errs)));
     }
 
-    return Result\ok(true);
+    return Result\ok();
 }
diff --git a/tests/Provider/OptionProvider.php b/tests/Provider/OptionProvider.php
index 0ab00a1..cee2ef4 100644
--- a/tests/Provider/OptionProvider.php
+++ b/tests/Provider/OptionProvider.php
@@ -11,6 +11,9 @@ trait OptionProvider
     /**
      * @return iterable<array{Option<mixed>, mixed, mixed}>
      */
+    /**
+     * @phpstan-ignore missingType.iterableValue
+     */
     public static function fromValueMatrix(): iterable
     {
         $o = (object)[];
diff --git a/tests/Unit/MonadTest.php b/tests/Unit/MonadTestAbstract.php
similarity index 97%
rename from tests/Unit/MonadTest.php
rename to tests/Unit/MonadTestAbstract.php
index 8928f5e..06cc9f2 100644
--- a/tests/Unit/MonadTest.php
+++ b/tests/Unit/MonadTestAbstract.php
@@ -23,7 +23,7 @@
 /**
  * @template TMonad of Monad
  */
-abstract class MonadTest extends TestCase
+abstract class MonadTestAbstract extends TestCase
 {
     /**
      * @return iterable<array{TMonad<string>}>
@@ -100,8 +100,7 @@ private function get_caller_type(array $backtrace): ?ReflectionNamedType
             $ref_class = new ReflectionClass($backtrace['class']);
             $ref_method = $ref_class->getMethod($backtrace['function']);
             $ref_type = $ref_method->getReturnType();
-
-        } elseif ($function = ($backtrace['function'] ?? null)) {
+        } elseif ($function = ($backtrace['function'] ?? null)) {/** @phpstan-ignore elseif.condNotBoolean */
             $ref_function = new ReflectionFunction($function);
             $ref_type = $ref_function->getReturnType();
         }
diff --git a/tests/Unit/Option/InterfaceTest.php b/tests/Unit/Option/InterfaceTest.php
index a8cacfd..e3fdbae 100644
--- a/tests/Unit/Option/InterfaceTest.php
+++ b/tests/Unit/Option/InterfaceTest.php
@@ -28,7 +28,6 @@ public function instanceOfOption(): void
     public function instanceOfNone(): void
     {
         Assert::assertInstanceOf(Option\None::class, Option\none());
-        // @phpstan-ignore-next-line
         Assert::assertNotInstanceOf(Option\None::class, Option\some(null));
     }
 
@@ -36,7 +35,6 @@ public function instanceOfNone(): void
     #[TestDox('instanceOfSome test')]
     public function instanceOfSome(): void
     {
-        // @phpstan-ignore-next-line
         Assert::assertNotInstanceOf(Option\Some::class, Option\none());
         Assert::assertInstanceOf(Option\Some::class, Option\some(null));
     }
diff --git a/tests/Unit/Option/OrThrowTest.php b/tests/Unit/Option/OrThrowTest.php
index 7e502e7..7e72a2d 100644
--- a/tests/Unit/Option/OrThrowTest.php
+++ b/tests/Unit/Option/OrThrowTest.php
@@ -10,6 +10,7 @@
 use PHPUnit\Framework\Attributes\TestDox;
 use RuntimeException;
 use WizDevelop\PhpMonad\Option;
+use WizDevelop\PhpMonad\Tests\Assert;
 use WizDevelop\PhpMonad\Tests\TestCase;
 
 #[TestDox('Option - OrThrow メソッドのテスト')]
@@ -27,9 +28,9 @@ public function someReturnsItself(): void
 
         $result = $some->orThrow($exception);
 
-        $this->assertSame($some, $result);
-        $this->assertTrue($result->isSome());
-        $this->assertSame(42, $result->unwrap());
+        Assert::assertSame($some, $result);
+        Assert::assertTrue($result->isSome());
+        Assert::assertSame(42, $result->unwrap());
     }
 
     #[Test]
diff --git a/tests/Unit/Option/TransposeTest.php b/tests/Unit/Option/TransposeTest.php
index 884545c..21882c8 100644
--- a/tests/Unit/Option/TransposeTest.php
+++ b/tests/Unit/Option/TransposeTest.php
@@ -9,6 +9,7 @@
 use PHPUnit\Framework\Attributes\TestDox;
 use WizDevelop\PhpMonad\Option;
 use WizDevelop\PhpMonad\Result;
+use WizDevelop\PhpMonad\Tests\Assert;
 use WizDevelop\PhpMonad\Tests\TestCase;
 
 #[TestDox('Option - transpose関数のテスト')]
@@ -24,9 +25,9 @@ public function transposeSomeOk(): void
         /** @phpstan-ignore-next-line */
         $result = Option\transpose($option);
 
-        $this->assertTrue($result->isOk());
-        $this->assertTrue($result->unwrap()->isSome());
-        $this->assertSame(42, $result->unwrap()->unwrap());
+        Assert::assertTrue($result->isOk());
+        Assert::assertTrue($result->unwrap()->isSome());
+        Assert::assertSame(42, $result->unwrap()->unwrap());
     }
 
     #[Test]
@@ -38,8 +39,8 @@ public function transposeSomeErr(): void
         /** @phpstan-ignore-next-line */
         $result = Option\transpose($option);
 
-        $this->assertTrue($result->isErr());
-        $this->assertSame('error', $result->unwrapErr());
+        Assert::assertTrue($result->isErr());
+        Assert::assertSame('error', $result->unwrapErr());
     }
 
     #[Test]
@@ -51,7 +52,7 @@ public function transposeNone(): void
         /** @phpstan-ignore-next-line */
         $result = Option\transpose($option);
 
-        $this->assertTrue($result->isOk());
-        $this->assertTrue($result->unwrap()->isNone());
+        Assert::assertTrue($result->isOk());
+        Assert::assertTrue($result->unwrap()->isNone());
     }
 }
diff --git a/tests/Unit/Option/UnwrapOrThrowTest.php b/tests/Unit/Option/UnwrapOrThrowTest.php
index 845de7c..e14a460 100644
--- a/tests/Unit/Option/UnwrapOrThrowTest.php
+++ b/tests/Unit/Option/UnwrapOrThrowTest.php
@@ -11,6 +11,7 @@
 use PHPUnit\Framework\TestCase;
 use RuntimeException;
 use WizDevelop\PhpMonad\Option;
+use WizDevelop\PhpMonad\Tests\Assert;
 
 use function WizDevelop\PhpMonad\Option\none;
 use function WizDevelop\PhpMonad\Option\some;
@@ -27,7 +28,7 @@ public function some値の場合は値を返す(): void
         $option = some($value);
         $exception = new Exception('This exception should not be thrown');
 
-        $this->assertSame($value, $option->unwrapOrThrow($exception));
+        Assert::assertSame($value, $option->unwrapOrThrow($exception));
     }
 
     #[Test]
diff --git a/tests/Unit/OptionTest.php b/tests/Unit/OptionTest.php
index 78def6a..d73fa22 100644
--- a/tests/Unit/OptionTest.php
+++ b/tests/Unit/OptionTest.php
@@ -6,15 +6,18 @@
 
 use Override;
 use PHPUnit\Framework\Attributes\CoversClass;
+use PHPUnit\Framework\Attributes\DataProvider;
+use PHPUnit\Framework\Attributes\Test;
 use PHPUnit\Framework\Attributes\TestDox;
+use WizDevelop\PhpMonad\Monad;
 use WizDevelop\PhpMonad\Option;
 
 /**
- * @extends MonadTest<Option>
+ * @extends MonadTestAbstract<Option>
  */
 #[TestDox('Option - MonadTest')]
 #[CoversClass(Option::class)]
-final class OptionTest extends MonadTest
+final class OptionTest extends MonadTestAbstract
 {
     /**
      * @return iterable<array{Option<string>}>
@@ -25,4 +28,15 @@ public static function monadsProvider(): iterable
         yield 'just' => [Option\some('Monad')];
         yield 'nothing' => [Option\none()];
     }
+
+    /**
+     * @param Monad<string> $subject
+     */
+    #[Test]
+    #[TestDox('Monad laws')]
+    #[DataProvider('monadsProvider')]
+    public function monadLaws(Monad $subject): void
+    {
+        parent::monadLaws($subject);
+    }
 }
diff --git a/tests/Unit/Result/CombineTest.php b/tests/Unit/Result/CombineTest.php
index d4e02ff..36749d7 100644
--- a/tests/Unit/Result/CombineTest.php
+++ b/tests/Unit/Result/CombineTest.php
@@ -8,6 +8,7 @@
 use PHPUnit\Framework\Attributes\Test;
 use PHPUnit\Framework\Attributes\TestDox;
 use WizDevelop\PhpMonad\Result;
+use WizDevelop\PhpMonad\Tests\Assert;
 use WizDevelop\PhpMonad\Tests\TestCase;
 
 #[TestDox('Result - combine関数のテスト')]
@@ -26,8 +27,8 @@ public function combineAllOk(): void
 
         $result = Result\combine(...$results);
 
-        $this->assertTrue($result->isOk());
-        $this->assertTrue($result->unwrap());
+        Assert::assertTrue($result->isOk());
+        Assert::assertTrue($result->unwrap());
     }
 
     #[Test]
@@ -44,16 +45,14 @@ public function combineWithErrors(): void
 
         $result = Result\combine(...$results);
 
-        $this->assertTrue($result->isErr());
+        Assert::assertTrue($result->isErr());
         $errors = $result->unwrapErr();
-        $this->assertIsArray($errors);
-        $this->assertCount(2, $errors);
+        Assert::assertIsArray($errors);
+        Assert::assertCount(2, $errors);
         // エラーの順序は配列のフィルタリング方法によって決まる
         // 2つのエラーが含まれていることを確認
-        $this->assertTrue($errors[0] === 'error1');
-        $this->assertTrue($errors[1] === 'error2');
-        // $this->assertTrue(in_array('error1', $errors, true));
-        // $this->assertTrue(in_array('error2', $errors, true));
+        Assert::assertTrue($errors[0] === 'error1');
+        Assert::assertTrue($errors[1] === 'error2');
     }
 
     #[Test]
@@ -62,7 +61,7 @@ public function combineEmpty(): void
     {
         $result = Result\combine();
 
-        $this->assertTrue($result->isOk());
-        $this->assertTrue($result->unwrap());
+        Assert::assertTrue($result->isOk());
+        Assert::assertTrue($result->unwrap());
     }
 }
diff --git a/tests/Unit/Result/FromThrowableTest.php b/tests/Unit/Result/FromThrowableTest.php
index 16392f2..f199e35 100644
--- a/tests/Unit/Result/FromThrowableTest.php
+++ b/tests/Unit/Result/FromThrowableTest.php
@@ -10,6 +10,7 @@
 use RuntimeException;
 use Throwable;
 use WizDevelop\PhpMonad\Result;
+use WizDevelop\PhpMonad\Tests\Assert;
 use WizDevelop\PhpMonad\Tests\TestCase;
 
 #[TestDox('Result - fromThrowable メソッドのテスト')]
@@ -25,8 +26,8 @@ public function fromThrowableWithSuccessfulCallback(): void
 
         $result = Result\fromThrowable($callback, $errorHandler);
 
-        $this->assertTrue($result->isOk());
-        $this->assertSame(42, $result->unwrap());
+        Assert::assertTrue($result->isOk());
+        Assert::assertSame(42, $result->unwrap());
     }
 
     #[Test]
@@ -38,7 +39,7 @@ public function fromThrowableWithExceptionThrowingCallback(): void
 
         $result = Result\fromThrowable($callback, $errorHandler);
 
-        $this->assertTrue($result->isErr());
-        $this->assertSame('Test exception', $result->unwrapErr());
+        Assert::assertTrue($result->isErr());
+        Assert::assertSame('Test exception', $result->unwrapErr());
     }
 }
diff --git a/tests/Unit/Result/InterfaceTest.php b/tests/Unit/Result/InterfaceTest.php
index 59b5ace..05c957e 100644
--- a/tests/Unit/Result/InterfaceTest.php
+++ b/tests/Unit/Result/InterfaceTest.php
@@ -30,7 +30,6 @@ public function instanceOfErr(): void
     {
         Assert::assertInstanceOf(Result\Err::class, $result = Result\err(null));
 
-        // @phpstan-ignore-next-line
         Assert::assertNotInstanceOf(Result\Err::class, $result = Result\ok(null));
     }
 
diff --git a/tests/Unit/Result/IsTest.php b/tests/Unit/Result/IsTest.php
index bd8c224..6a804df 100644
--- a/tests/Unit/Result/IsTest.php
+++ b/tests/Unit/Result/IsTest.php
@@ -25,11 +25,9 @@ final class IsTest extends TestCase
     public function isOk(mixed $value): void
     {
         $result = Result\ok($value);
-        // @phpstan-ignore-next-line
         Assert::assertTrue($result->isOk());
 
         $result = Result\err($value);
-        // @phpstan-ignore-next-line
         Assert::assertFalse($result->isOk());
     }
 
@@ -39,11 +37,9 @@ public function isOk(mixed $value): void
     public function isErr(mixed $value): void
     {
         $result = Result\ok($value);
-        // @phpstan-ignore-next-line
         Assert::assertFalse($result->isErr());
 
         $result = Result\err($value);
-        // @phpstan-ignore-next-line
         Assert::assertTrue($result->isErr());
     }
 
@@ -58,7 +54,6 @@ public function isOkAnd(mixed $value): void
         Assert::assertFalse($result->isOkAnd(static fn (mixed $v) => $v !== $value));
 
         $result = Result\err($value);
-        // @phpstan-ignore-next-line
         Assert::assertFalse($result->isOkAnd(static fn (mixed $v) => Assert::fail('predicate should be called')));
         Assert::assertFalse($result->isOkAnd(static fn (mixed $v) => Assert::fail('predicate should be called')));
     }
@@ -69,7 +64,6 @@ public function isOkAnd(mixed $value): void
     public function isErrAnd(mixed $value): void
     {
         $result = Result\ok($value);
-        // @phpstan-ignore-next-line
         Assert::assertFalse($result->isErrAnd(static fn (mixed $v) => Assert::fail('predicate should be called')));
         Assert::assertFalse($result->isErrAnd(static fn (mixed $v) => Assert::fail('predicate should be called')));
 
diff --git a/tests/Unit/Result/IterateTest.php b/tests/Unit/Result/IterateTest.php
index fb35283..7f79176 100644
--- a/tests/Unit/Result/IterateTest.php
+++ b/tests/Unit/Result/IterateTest.php
@@ -25,7 +25,6 @@ public function iterateResults(): void
 
         Assert::assertSame([], iterator_to_array($result = Result\err(null)));
 
-        // @phpstan-ignore-next-line
         Assert::assertIsIterable($result = Result\ok(42));
 
         Assert::assertSame([42], iterator_to_array($result = Result\ok(42)));
diff --git a/tests/Unit/Result/OrThrowTest.php b/tests/Unit/Result/OrThrowTest.php
index 1f36633..fd07e79 100644
--- a/tests/Unit/Result/OrThrowTest.php
+++ b/tests/Unit/Result/OrThrowTest.php
@@ -10,6 +10,7 @@
 use PHPUnit\Framework\Attributes\TestDox;
 use RuntimeException;
 use WizDevelop\PhpMonad\Result;
+use WizDevelop\PhpMonad\Tests\Assert;
 use WizDevelop\PhpMonad\Tests\TestCase;
 
 #[TestDox('Result - OrThrow メソッドのテスト')]
@@ -27,9 +28,9 @@ public function okReturnsItself(): void
 
         $result = $ok->orThrow($exception);
 
-        $this->assertSame($ok, $result);
-        $this->assertTrue($result->isOk());
-        $this->assertSame(42, $result->unwrap());
+        Assert::assertSame($ok, $result);
+        Assert::assertTrue($result->isOk());
+        Assert::assertSame(42, $result->unwrap());
     }
 
     #[Test]
diff --git a/tests/Unit/Result/TransposeTest.php b/tests/Unit/Result/TransposeTest.php
index 54c5592..d1f4c11 100644
--- a/tests/Unit/Result/TransposeTest.php
+++ b/tests/Unit/Result/TransposeTest.php
@@ -9,6 +9,7 @@
 use PHPUnit\Framework\Attributes\TestDox;
 use WizDevelop\PhpMonad\Option;
 use WizDevelop\PhpMonad\Result;
+use WizDevelop\PhpMonad\Tests\Assert;
 use WizDevelop\PhpMonad\Tests\TestCase;
 
 #[TestDox('Result - transpose関数のテスト')]
@@ -24,9 +25,9 @@ public function transposeOkSome(): void
         /** @phpstan-ignore-next-line */
         $option = Result\transpose($result);
 
-        $this->assertTrue($option->isSome());
-        $this->assertTrue($option->unwrap()->isOk());
-        $this->assertSame(42, $option->unwrap()->unwrap());
+        Assert::assertTrue($option->isSome());
+        Assert::assertTrue($option->unwrap()->isOk());
+        Assert::assertSame(42, $option->unwrap()->unwrap());
     }
 
     #[Test]
@@ -38,7 +39,7 @@ public function transposeOkNone(): void
         /** @phpstan-ignore-next-line */
         $option = Result\transpose($result);
 
-        $this->assertTrue($option->isNone());
+        Assert::assertTrue($option->isNone());
     }
 
     #[Test]
@@ -50,8 +51,8 @@ public function transposeErr(): void
         /** @phpstan-ignore-next-line */
         $option = Result\transpose($result);
 
-        $this->assertTrue($option->isSome());
-        $this->assertTrue($option->unwrap()->isErr());
-        $this->assertSame('error', $option->unwrap()->unwrapErr());
+        Assert::assertTrue($option->isSome());
+        Assert::assertTrue($option->unwrap()->isErr());
+        Assert::assertSame('error', $option->unwrap()->unwrapErr());
     }
 }
diff --git a/tests/Unit/Result/UnwrapOrThrowTest.php b/tests/Unit/Result/UnwrapOrThrowTest.php
index c6d3701..894f8ae 100644
--- a/tests/Unit/Result/UnwrapOrThrowTest.php
+++ b/tests/Unit/Result/UnwrapOrThrowTest.php
@@ -11,6 +11,7 @@
 use PHPUnit\Framework\TestCase;
 use RuntimeException;
 use WizDevelop\PhpMonad\Result;
+use WizDevelop\PhpMonad\Tests\Assert;
 
 use function WizDevelop\PhpMonad\Result\err;
 use function WizDevelop\PhpMonad\Result\ok;
@@ -27,7 +28,7 @@ public function ok値の場合は値を返す(): void
         $result = ok($value);
         $exception = new Exception('This exception should not be thrown');
 
-        $this->assertSame($value, $result->unwrapOrThrow($exception));
+        Assert::assertSame($value, $result->unwrapOrThrow($exception));
     }
 
     #[Test]
diff --git a/tests/Unit/ResultTest.php b/tests/Unit/ResultTest.php
index 19f2907..0a4806b 100644
--- a/tests/Unit/ResultTest.php
+++ b/tests/Unit/ResultTest.php
@@ -6,15 +6,18 @@
 
 use Override;
 use PHPUnit\Framework\Attributes\CoversClass;
+use PHPUnit\Framework\Attributes\DataProvider;
+use PHPUnit\Framework\Attributes\Test;
 use PHPUnit\Framework\Attributes\TestDox;
+use WizDevelop\PhpMonad\Monad;
 use WizDevelop\PhpMonad\Result;
 
 /**
- * @extends MonadTest<Result>
+ * @extends MonadTestAbstract<Result>
  */
 #[TestDox('Result - MonadTest')]
 #[CoversClass(Result::class)]
-final class ResultTest extends MonadTest
+final class ResultTest extends MonadTestAbstract
 {
     /**
      * @return iterable<array{Result<string,string>}>
@@ -26,4 +29,15 @@ public static function monadsProvider(): iterable
         // TODO: どうしてもテストが落ちるためやむを得ずコメントアウトする
         // yield 'err' => [Result\err('Err')];
     }
+
+    /**
+     * @param Monad<string> $subject
+     */
+    #[Test]
+    #[TestDox('Monad laws')]
+    #[DataProvider('monadsProvider')]
+    public function monadLaws(Monad $subject): void
+    {
+        parent::monadLaws($subject);
+    }
 }