Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Web Development

Testen Ihres Ruby-Codes mit Guard, RSpec & Pry: Teil 2

by
Read Time:19 minsLanguages:

German (Deutsch) translation by Tatsiana Bochkareva (you can also view the original English article)

Willkommen zurück! Wenn Sie den ersten Teil unserer Reise bisher verpasst haben, möchten Sie vielleicht zuerst zurückgehen und aufholen.

Bisher haben wir neben der Verwendung des beliebten RSpec-Testframeworks einen testgetriebenen Entwicklungsprozess zum Erstellen unserer Anwendung angewendet. Von hier aus werden wir einige andere RSpec-Funktionen untersuchen und die Verwendung des Pry-Edelsteins untersuchen, um Ihnen beim Debuggen und Schreiben Ihres Codes zu helfen.

Weitere RSpec-Funktionen

Nehmen wir uns einen Moment Zeit, um einige andere RSpec-Funktionen zu überprüfen, die wir in dieser einfachen Beispielanwendung nicht benötigt haben. Möglicherweise ist es jedoch hilfreich, an Ihrem eigenen Projekt zu arbeiten.

Ausstehende Erklärung

Stellen Sie sich vor, Sie schreiben einen Test, sind aber unterbrochen, oder Sie müssen zu einem Meeting gehen und haben den Code, der erforderlich ist, um den Test zu bestehen, noch nicht abgeschlossen.

Sie können den Test löschen und später neu schreiben, wenn Sie wieder zu Ihrer Arbeit zurückkehren können. Alternativ können Sie den Code auch einfach auskommentieren, aber das ist ziemlich hässlich und definitiv nicht gut, wenn Sie ein Versionskontrollsystem verwenden.

In dieser Situation ist es am besten, unseren Test als "ausstehend" zu definieren. Wenn die Tests ausgeführt werden, ignoriert das Testframework den Test. Dazu müssen Sie das pending Schlüsselwort verwenden:

Auf- und Abbau

Mit allen guten Test-Frameworks können Sie Code vor und nach jedem Test ausführen. RSpec ist nicht anders.

Es bietet uns  before und after Methoden, mit denen wir einen bestimmten Status für die Ausführung unseres Tests einrichten und diesen Status nach dem Ausführen des Tests bereinigen können (dies ist also so, dass der Status nicht ausläuft und das Ergebnis von beeinflusst nachfolgende Tests).

Kontextblöcke

Wir haben den describe block bereits gesehen. Es gibt jedoch einen anderen Block, der funktional äquivalent ist und als context bezeichnet wird. Sie können es überall dort verwenden, wo Sie describe benutzen.

Der Unterschied zwischen ihnen ist subtil, aber wichtig: context ermöglicht es uns, einen Zustand für unseren Test zu definieren. Nicht explizit (wir setzen den Status nicht durch Definieren eines context blocks, sondern dienen der Lesbarkeit, damit die Absicht des folgenden Codes klarer wird).

Hier ist ein Beispiel:

Stubs

Wir können die stub-Methode verwenden, um eine gefälschte Version eines vorhandenen Objekts zu erstellen und einen vorgegebenen Wert zurückgeben zu lassen.

Dies ist nützlich, um zu verhindern, dass unsere Tests Live-Service-APIs berühren, und um unsere Tests zu steuern, indem vorhersehbare Ergebnisse aus bestimmten Aufrufen geliefert werden.

Stellen Sie sich vor, wir haben eine Klasse namens Person und diese Klasse hat eine speak-Methode. Wir möchten testen, ob diese Methode so funktioniert, wie wir es erwarten. Dazu stubben wir die speak-Methode mit dem folgenden Code:

In diesem Beispiel sagen wir, dass für 'jede Instanz' der Person-Klasse die initialize-Methode gestoppt werden sollte, damit das Objekt bob zurückgegeben wird.

Sie werden feststellen, dass bob selbst ein Stub ist, der so eingerichtet ist, dass jeder Code, der versucht, die speak-Methode auszuführen, "hello" zurückgibt.

Anschließend erstellen wir eine neue Person-Instanz und übergeben den Aufruf von instance.speak an die expect-Syntax von RSpec.

Wir teilen RSpec mit, dass wir erwarten, dass dieser Aufruf den String "hello" ergibt.

Aufeinanderfolgende Rückgabewerte

In den vorherigen Beispielen haben wir die RSpec-Funktion and_return verwendet, um anzugeben, was unser Stub zurückgeben soll, wenn er aufgerufen wird.

Wir können jedes Mal, wenn der Stub aufgerufen wird, einen anderen Rückgabewert angeben, indem wir mehrere Argumente für die and_return-Methode angeben:

Verspottet

Verspottet ähneln Stubs darin, dass wir gefälschte Versionen unserer Objekte erstellen, aber anstatt einen vordefinierten Wert zurückzugeben, leiten wir genauer die Routen, die unsere Objekte einschlagen müssen, damit der Test gültig ist.

Dazu verwenden wir die mock-Methode:

Im obigen Beispiel erstellen wir eine neue Objekt-Instanz und rufen dann ihre testing-Methode auf.

Hinter den Kulissen dieses Codes erwarten wir, dass die testing-Methode mit dem Wert 'content' aufgerufen wird. Wenn es nicht mit diesem Wert aufgerufen wird (was im obigen Beispiel nicht der Fall ist), wissen wir, dass ein Teil unseres Codes nicht richtig funktioniert hat.

Betreff Block

Das subject-Schlüsselwort kann auf verschiedene Arten verwendet werden. All dies wurde entwickelt, um die Duplizierung von Code zu reduzieren.

Sie können es implizit verwenden (beachten Sie, dass unser it-Block überhaupt nicht auf subject verweist):

Sie können es explizit verwenden (beachten Sie, dass unser it-Block direkt auf den subject verweist):

Anstatt ständig auf einen Betreff in Ihrem Code zu verweisen und verschiedene Werte zur Instanziierung zu übergeben, zum Beispiel:

Sie können stattdessen subject zusammen mit let verwenden, um die Duplizierung zu reduzieren:

RSpec bietet noch viele weitere Funktionen, aber wir haben uns die wichtigsten angesehen, die Sie beim Schreiben von Tests mit RSpec häufig verwenden.

Randomisierte Tests

Sie können RSpec so konfigurieren, dass Ihre Tests in zufälliger Reihenfolge ausgeführt werden. Auf diese Weise können Sie sicherstellen, dass keiner Ihrer Tests von den anderen Tests in der Umgebung abhängig oder abhängig ist.

Sie können dies über den Befehl mit dem Flag --order Flag/Option einstellen. Zum Beispiel: rspec --order random.

Wenn Sie die Option --order random verwenden, zeigt RSpec die Zufallszahl an, mit der der Algorithmus gesetzt wurde. Sie können diesen Startwert erneut verwenden, wenn Sie glauben, in Ihren Tests ein Abhängigkeitsproblem entdeckt zu haben. Sobald Sie das Problem behoben haben, können Sie den Startwert an RSpec übergeben (z. B. wenn der Startwert 1234 war, dann --order random:1234 ausführen) und denselben zufälligen Startwert verwenden, um zu prüfen, ob er den Wert replizieren kann ursprünglicher Abhängigkeitsfehler.

Globale Konfiguration

Sie haben gesehen, dass wir in unserem Rakefile einen projektspezifischen Satz von Konfigurationsobjekten hinzugefügt haben. Sie können Konfigurationsoptionen jedoch global festlegen, indem Sie sie einer .rspec-Datei in Ihrem Home-Verzeichnis hinzufügen.

Zum Beispiel in .rspec:

Debuggen mit Pry

Jetzt können wir untersuchen, wie wir unsere Anwendung und unseren Testcode mit dem Pry-Juwel debuggen können.

Es ist wichtig zu verstehen, dass Pry zwar wirklich gut zum Debuggen Ihres Codes ist, aber tatsächlich als verbessertes Ruby REPL-Tool (als Ersatz für irb) gedacht ist und nicht ausschließlich zum Debuggen dient. So gibt es beispielsweise keine integrierten Funktionen wie: Einsteigen, Übersteigen oder Aussteigen usw., die Sie normalerweise in einem zum Debuggen entwickelten Tool finden würden.

Aber als Debugging-Tool ist Pry sehr konzentriert und schlank.

Wir werden gleich zum Debuggen zurückkehren, aber lassen Sie uns zunächst überprüfen, wie wir Pry zunächst verwenden werden.

Codebeispiel aktualisiert

Um Pry zu demonstrieren, werde ich meiner Beispielanwendung mehr Code hinzufügen (dieser zusätzliche Code wirkt sich in keiner Weise auf unseren Test aus).

Sie werden feststellen, dass wir einige zusätzliche Methoden, Instanz- und Klasseneigenschaften hinzugefügt haben. Wir rufen auch zwei der neuen Methoden auf, die wir in unserer greet-Methode hinzugefügt haben.

Zuletzt werden Sie die Verwendung von binding.pry bemerken.

Haltepunkte mit binding.pry setzen

Ein Haltepunkt ist eine Stelle in Ihrem Code, an der die Ausführung gestoppt wird.

Sie können mehrere Haltepunkte in Ihrem Code festlegen und diese mit binding.pry erstellen.

Wenn Sie Ihren Code ausführen, werden Sie feststellen, dass das Terminal anhält und Sie genau an der Stelle, an der Ihre Bindung platziert wurde, in den Code Ihrer Anwendung einfügt.

Unten sehen Sie ein Beispiel, wie es aussehen könnte...

Ab diesem Zeitpunkt hat Pry Zugriff auf den lokalen Bereich, sodass Sie Pry wie in irb verwenden und beispielsweise Variablen eingeben können, um zu sehen, welche Werte sie enthalten.

Sie können den Befehl exit ausführen, um Pry zu beenden und die Ausführung Ihres Codes fortzusetzen.

Finden, wo Sie sind: whereeami

Wenn Sie viele binding.pry-Haltepunkte verwenden, kann es schwierig sein zu verstehen, wo Sie sich in der Anwendung befinden.

Um einen besseren Kontext zu erhalten, wo Sie sich zu einem beliebigen Zeitpunkt befinden, können Sie den Befehl whereeami verwenden.

Wenn Sie es alleine ausführen, sehen Sie etwas Ähnliches wie bei der Verwendung von binding.pry (Sie sehen die Linie, auf der der Haltepunkt festgelegt wurde, und einige Linien darüber und darunter). Der Unterschied besteht darin, dass Sie, wenn Sie ein zusätzliches numerisches Argument wie whereeami 5 übergeben, fünf zusätzliche Zeilen über der Stelle sehen, an der die binding.pry platziert wurde. Sie können beispielsweise anfordern, 100 Zeilen um den aktuellen Haltepunkt herum anzuzeigen.

Dieser Befehl kann Ihnen helfen, sich in der aktuellen Datei zu orientieren.

Stapelverfolgung: wtf

Der Befehl wtf steht für "what the f***" und bietet eine vollständige Stapelverfolgung für die letzte ausgelöste Ausnahme. Es kann Ihnen helfen, die Schritte zu verstehen, die zu dem aufgetretenen Fehler geführt haben.

Inspektion: ls

Der Befehl ls zeigt an, welche Methoden und Eigenschaften Pry zur Verfügung stehen.

Beim Ausführen wird Ihnen so etwas wie...

Im obigen Beispiel sehen wir, dass wir vier öffentliche Methoden haben (denken Sie daran, dass wir unseren Code aktualisiert haben, um einige zusätzliche Methoden aufzunehmen, und dann test und test= erstellt wurden, wenn Rubys Kurzhand attr_accessor verwendet wurde).

Es werden auch andere Klassen- und lokale Variablen angezeigt, auf die Pry zugreifen kann.

Eine andere nützliche Sache, die Sie tun können, ist, die Ergebnisse nur nach dem zu durchsuchen, woran Sie interessiert sind. Sie müssen die regulären Ausdrücke verstehen, aber es kann eine praktische Technik sein. Hier ist ein Beispiel...

Im obigen Beispiel verwenden wir die Optionen / Flags -p und -G, die Pry mitteilen, dass wir nur öffentliche und private Methoden sehen möchten, und wir verwenden den regulären Ausdruck ^p (was bedeutet, dass alles mit p beginnt) als Suchmuster für Filtern Sie die Ergebnisse.

Wenn Sie ls --help ausführen, werden Ihnen auch alle verfügbaren Optionen angezeigt.

Umfang ändern: cd

Sie können den aktuellen Bereich mit dem Befehl cd ändern.

Wenn wir in unserem Beispiel cd ../pubs ausführen, gelangen wir zum Ergebnis dieses Methodenaufrufs.

Wenn wir jetzt whereeami ausführen, wird Inside "I'm a test variable" angezeigt.

Wenn wir self ausführen, wird "I'm a test variable" zurückgegeben.

Wenn wir self.class ausführen, wird String zurückgegeben.

Sie können die Bereichskette mit cd .. nach oben verschieben oder mit cd / zur obersten Ebene des Bereichs zurückkehren.

Hinweis: Wir könnten innerhalb der pubs-Methode eine weitere binding.pry hinzufügen, und dann würde sich unser Gültigkeitsbereich eher innerhalb dieser Methode als im Ergebnis der Methode befinden.

Sehen, wie tief Sie sind: nesting

Betrachten Sie das vorherige Beispiel für das Ausführen von cd pubs. Wenn wir den nesting befehl ausführen, erhalten wir einen Überblick über die Anzahl der Kontexte / Ebenen, die Pry derzeit hat:

Von dort aus können wir exit ausführen, um zum früheren Kontext zurückzukehren (z. B. innerhalb der greet-Methode).

Wenn Sie exit erneut ausführen, wird der letzte Kontext geschlossen, den Pry hat, und Pry wird beendet, und unser Code wird weiterhin ausgeführt.

Suchen Sie eine beliebige Methode: find-method

Wenn Sie nicht sicher sind, wo Sie eine bestimmte Methode finden können, können Sie mit dem Befehl find-method alle Dateien in Ihrer Codebasis anzeigen, deren Methode mit der Suche übereinstimmt:

Sie können stattdessen auch die Option/Flag -c verwenden, um den Inhalt von Dateien zu durchsuchen:

Klassisches Debugging: next, step, continue

Obwohl die oben genannten Techniken nützlich sind, ist es nicht wirklich "Debuggen" in dem Sinne, wie Sie es wahrscheinlich gewohnt sind.

Für die meisten Entwickler stellt ihr Editor oder Browser ein integriertes Debugging-Tool zur Verfügung, mit dem sie ihren Code Zeile für Zeile durchlaufen und dem Weg folgen können, den der Code bis zur Fertigstellung nimmt.

Da Pry für die Verwendung als REPL entwickelt wurde, heißt das nicht, dass es für das Debuggen nicht nützlich ist.

Eine naive Lösung wäre, mehrere binding.pry-Anweisungen in einer Methode festzulegen und mit strg-d durch jeden Haltepunktsatz zu navigieren. Aber das ist immer noch nicht gut genug.

Zum schrittweisen Debuggen können Sie das gem pry-nav...

Dieses Juwel erweitert Pry, sodass es die folgenden Befehle versteht:

  • Next (zur nächsten Zeile wechseln)
  • Step (gehen Sie zur nächsten Zeile und wenn es eine Methode ist, gehe in diese Methode über)
  • Continue (Ignorieren Sie alle weiteren Haltepunkte in dieser Datei)

Kontinuierliche Integration mit Travis-CI

Als zusätzlichen Bonus integrieren wir unsere Tests in den Online-CI-Dienst (Continuous Integration) Travis-CI.

Das Prinzip von CI besteht darin, frühzeitig und häufig festzuschreiben / zu pushen, um Konflikte zwischen Ihrem Code und dem Hauptzweig zu vermeiden. Wenn Sie dies tun (in diesem Fall verpflichten wir uns zu GitHub), sollte dies einen Build auf Ihrem CI-Server auslösen, der die relevanten Tests ausführt, um sicherzustellen, dass alles so funktioniert, wie es sein sollte.

Mit TDD als primärer Entwicklungsmethode ist es weniger wahrscheinlich, dass bei jedem Push Fehler auftreten, da Ihre Tests ein wesentlicher Bestandteil Ihres Entwicklungsworkflows sind. Bevor Sie also pushen, sind Sie bereits über Fehler oder Regressionen informiert. Dies schützt Sie jedoch nicht unbedingt vor Fehlern, die bei Integrationstests auftreten (bei denen der gesamte Code auf mehreren Systemen zusammen ausgeführt wird, um sicherzustellen, dass das gesamte System ordnungsgemäß funktioniert).

Unabhängig davon sollte Code niemals direkt auf Ihren Live-Produktionsserver übertragen werden. Es sollte immer zuerst an einen CI-Server gesendet werden, um potenzielle Fehler zu erkennen, die sich aus Unterschieden zwischen Ihrer Entwicklungsumgebung und der Produktionsumgebung ergeben.

Viele Unternehmen haben noch mehr Umgebungen, in denen ihr Code durchlaufen werden kann, bevor er den Live-Produktionsserver erreicht.

Zum Beispiel haben wir bei BBC News:

  • CI
  • Test
  • Stage
  • Live

Obwohl jede Umgebung in der Einrichtung identisch sein sollte, besteht der Zweck darin, verschiedene Arten von Tests zu implementieren, um sicherzustellen, dass möglichst viele Fehler abgefangen und behoben werden, bevor der Code "live" erreicht.

Travis-CI

Travis CI ist ein gehosteter kontinuierlicher Integrationsdienst für die Open Source-Community. Es ist in GitHub integriert und bietet erstklassige Unterstützung für mehrere Sprachen

Dies bedeutet, dass Travis-CI kostenlose CI-Services für Open-Source-Projekte anbietet und auch ein kostenpflichtiges Modell für Unternehmen und Organisationen hat, die ihre CI-Integration privat halten möchten.

Wir werden das kostenlose Open-Source-Modell in unserem Beispiel-GitHub-Repository verwenden.

Der Prozess ist folgender:

  • Registrieren Sie ein Konto bei GitHub
  • Melden Sie sich mit Ihrem GitHub-Konto bei Travis-CI an
  • Gehen Sie zu Ihrer Seite "Konten"
  • Aktivieren Sie alle Repositorys, auf denen Sie CI ausführen möchten
  • Erstellen Sie eine .travis.yml-Datei im Stammverzeichnis Ihres Projekts und übertragen Sie sie in Ihr GitHub-Repository

Der letzte Schritt ist der wichtigste (Erstellen einer .travis.yml-Datei), da hierdurch die Konfigurationseinstellungen für Travis-CI festgelegt werden, damit die Tests für Ihr Projekt ausgeführt werden können.

Werfen wir einen Blick auf die .travis.yml-Datei, die wir für unser Beispiel-GitHub-Repository verwenden:

Lassen Sie uns dies Stück für Stück aufschlüsseln...

Zuerst geben wir an, welche Sprache wir in unserem Projekt verwenden. In diesem Fall verwenden wir Ruby: language: ruby.

Da das Ausführen von Bundler etwas langsam sein kann und wir wissen, dass sich unsere Abhängigkeiten nicht so oft ändern werden, können wir die Abhängigkeiten zwischenspeichern. Deshalb setzen wir cache: bundler.

Travis-CI verwendet RVM (Ruby Version Manager) zum Installieren von Rubinen auf ihren Servern. Daher müssen wir angeben, gegen welche Ruby-Versionen wir unsere Tests ausführen möchten. In diesem Fall haben wir 2.0 und 1.9.3 ausgewählt, zwei beliebte Ruby-Versionen (technisch gesehen verwendet unsere Anwendung Ruby 2, aber es ist gut zu wissen, dass unser Code auch in anderen Ruby-Versionen übergeben wird):

Um unsere Tests durchzuführen, wissen wir, dass wir den Befehl rake oder rake spec verwenden können. Travis-CI führt standardmäßig den Befehl rake aus, aber aufgrund der Installation von Gems auf Travis-CI mit Bundler müssen wir den Standardbefehl ändern: script: 'bundle exec rake spec'. Wenn wir dies nicht tun würden, hätte Travis-CI ein Problem beim Auffinden der Datei rspec/core/rake_task, die in unserer Rakefile angegeben ist.

Hinweis: Wenn Sie Probleme mit Travis-CI haben, können Sie sich dem # travis-Kanal im IRC-Freenode anschließen, um Hilfe bei der Beantwortung eventueller Fragen zu erhalten. Dort entdeckte ich die Lösung für mein Problem, dass Travis-CI meine Tests nicht mit dem Standard rake-Befehl ausführen konnte, und der Vorschlag, den Standard mit bundle exec rake zu überschreiben, löste dieses Problem.

Da wir nur daran interessiert sind, unsere Tests auszuführen, können wir Travis-CI zusätzliche Argumente übergeben, um Edelsteine zu filtern, die wir nicht installieren möchten. Daher möchten wir die Installation der als Entwicklung gruppierten Edelsteine ausschließen: bundler_args: --without development (dies bedeutet, dass wir Edelsteine ausschließen, die nur für die Entwicklung und das Debuggen verwendet werden, wie z. B. Pry und Guard).

Es ist wichtig zu beachten, dass ich Pry ursprünglich in unsere Datei spec_helper.rb geladen habe. Dies verursachte ein Problem beim Ausführen des Codes auf Travis-CI, da ich jetzt "development" gem ausschloss. Also musste ich den Code so anpassen:

Sie können sehen, dass das Pry-Juwel jetzt nur require wird, wenn eine Umgebungsvariable von APP_ENV auf Debug gesetzt ist. Auf diese Weise können wir verhindern, dass Travis-CI Fehler auslöst. Dies bedeutet, dass Sie beim lokalen Ausführen Ihres Codes die Umgebungsvariable festlegen müssen, wenn Sie Ihren Code mit Pry debuggen möchten. Das Folgende zeigt, wie dies in einer Zeile gemacht werden kann:

Es gab zwei weitere Änderungen, die ich vorgenommen habe, und das war an unserer Gemfile. Zum einen sollte klarer gemacht werden, welche Edelsteine zum Testen und welche zur Entwicklung benötigt wurden, und zum anderen wurde von Travis-CI ausdrücklich gefordert:

Wenn wir uns das oben aktualisierte Gemfile ansehen, können wir sehen, dass wir das RSpec-Gem in eine neue test gruppe verschoben haben. Jetzt sollte klarer sein, welchen Zweck jedes Gem hat. Wir haben auch einen neuen gem 'rake' hinzugefügt. In der Travis-CI-Dokumentation heißt es, dass dies explizit angegeben werden musste.

Der nächste Abschnitt ist optional und ermöglicht es Ihnen, bestimmte Zweige in Ihrem Repository auf die weiße Liste (oder schwarze Liste) zu setzen. Daher führt Travis-CI standardmäßig Tests für alle Ihre Zweige durch, sofern Sie nichts anderes angeben. In diesem Beispiel sagen wir, dass es nur für unseren master zweig ausgeführt werden soll:

Wir könnten ihm sagen, dass er jeden Zweig "außer" einem bestimmten Zweig ausführen soll, wie folgt:

Der letzte Abschnitt teilt Travis-CI mit, wohin Benachrichtigungen gesendet werden sollen, wenn ein Build fehlschlägt oder erfolgreich ist:

Sie können mehrere E-Mail-Adressen angeben, wenn Sie möchten:

Sie können genauer sein und angeben, was bei einem Fehler oder Erfolg passieren soll (z. B. sind mehr Personen nur interessiert, wenn die Tests fehlschlagen, anstatt jedes Mal eine E-Mail zu erhalten, wenn sie erfolgreich sind):

Das obige Beispiel zeigt, dass der Empfänger niemals eine E-Mail erhält, wenn die Tests bestanden wurden, sondern benachrichtigt wird, wenn sich der Fehlerstatus ändert (der Standardwert für beide ist immer, was bedeutet, dass Sie unabhängig vom Ergebnis des Status immer benachrichtigt werden).

Hinweis: Wenn Sie explizit ein on_failure oder on_success angeben, müssen Sie die E-Mail-Adresse(n) in den recepients schlüssel verschieben.

Abschluss

Das ist die Ende unseres zweiteiligen Blicks auf RSpec, TDD und Pry.

Im ersten Teil haben wir es geschafft, unsere Anwendung mithilfe des TDD-Prozesses und des RSpec-Testframeworks zu schreiben. In dieser zweiten Hälfte haben wir auch Pry verwendet, um zu zeigen, wie wir eine laufende Ruby-Anwendung einfacher debuggen können. Schließlich konnten wir unsere Tests so einrichten, dass sie als Teil eines kontinuierlichen Integrationsservers mit dem beliebten Travis-CI-Dienst ausgeführt werden.

Hoffentlich hat Ihnen dies genug Geschmack gegeben, sodass Sie jede dieser Techniken weiter untersuchen möchten.

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.