2016-07-04 12 views
3

Angenommen, ich habe ein Haskell-Modul mit dem Namen Foo, definiert in src/Foo.hs. Nehmen Sie auch an, dass Foo einen Typ Bar exportiert.Vermeiden der Build-Abhängigkeit von QuickCheck beim Deklarieren einer beliebigen Instanz

Jetzt möchte ich Unit-Tests für Bar (für die gesamte Foo Modul, tatsächlich) schreiben, so werfe ich ein paar Quick Check Eigenschaften in test/FooTest.hs; aber hey, jetzt muss ich eine Arbitrary Instanz für Bar definieren.

Und das ist der Haken: in -Wall -Werror Modus erfordert ghc Instanz Deklarationen an einer von zwei Stellen angezeigt: in der gleichen Datei, wo der Typ definiert ist, oder wo die Klasse definiert ist. Aber ich möchte nicht mein Foo-Modul mit einer Build-Abhängigkeit von QuickCheck überladen, und ich kann natürlich keine Instanz von Bar zu QuickCheck hinzufügen.

Also wie mache ich meinen Datentyp eine Instanz von Arbitrary, nur für Unit-Tests, ohne eine Abhängigkeit von QuickCheck für Benutzer meines Moduls und ohne -Wall -Werror aus dem Fenster zu werfen?

Antwort

4

Erstellen Sie innerhalb der Testsuite einen neuen Typ, der Bar umschließt und die Arbitrary Instanz für den Newtyp definiert.

+0

Argh, wird der Text nie enden ?! ;) –

+0

@ Arek'Fu Das Boilerplate kann reduziert werden, indem sichere Zwänge nach Bedarf ausgenutzt werden. – chi

+0

@chi, es ist immer noch eine Menge Lärm, und Sie müssen auf unsichere Zwänge für GHC 7.6 zurückgreifen, wenn Sie das unterstützen. Ich sehe nicht, wie es sich für eine Testsuite lohnt. – dfeuer

3

Versuchen Sie ghc -Wall -Werror -Wno-orphans für das Testmodul.

Nicht genau perfekt, da es die Warnung für andere verwaiste Instanzen deaktiviert, aber ich glaube, es ist das nächste, das wir im Moment bekommen können.

Eine pragma "diese Warnung in der nächsten Zeile unterdrücken" wäre auch nett.

+0

Fast alle Argumente zum Vermeiden von Waisen gelten nicht für ausführbare Testsuite. Diese Option ist für mich viel attraktiver als die Verwendung von CPP, um zu bewirken, dass mein Modul in den Tests einen anderen Code enthält als für die Produktion. – Ben

+0

@Ben, in manchen Fällen ist das schon nötig. Testcode benötigt möglicherweise Zugriff auf andernfalls nicht exportierte Konstruktoren und Funktionen. Eine Option besteht darin, alle diese Komponenten bedingungslos zu exportieren, aber in einem großen und ausgereiften Modul, das dies nicht tut, müssen sorgfältige Tests auf mögliche Leistungsänderungen durchgeführt werden. Der Inliner behandelt exportierte und nicht-exportierte Bindungen unterschiedlich. – dfeuer

1

Sie können ein CPM-Makro TESTING bedingt definieren, wenn Sie die Testsuite kompilieren. Auf diese Weise können Sie Waisen vermeiden, aber nur wenn Sie die Abhängigkeit verwenden. Sie können eine ähnliche Verwendung eines solchen Makros im Paket containers sehen, aber dieses Paket verwendet derzeit verwaiste Instanzen für den speziellen Zweck, Arbitrary Instanzen zur Testsuite hinzuzufügen. Ich kann das bald ändern.