Giter Site home page Giter Site logo

gabrielfalcao / lettuce Goto Github PK

View Code? Open in Web Editor NEW
1.3K 51.0 326.0 14.77 MB

Behavior-driven-development tool for python, inspired by Cucumber for Ruby ⛺

Home Page: http://lettuce.it

License: GNU General Public License v3.0

CSS 1.46% JavaScript 1.48% Ruby 0.01% Python 93.02% Shell 0.06% Makefile 0.08% HTML 3.51% Gherkin 0.25% Batchfile 0.01% Roff 0.13% TSQL 0.01%
python bdd behavior-driven-development

lettuce's Introduction

lettuce

Version 0.2.23 - kryptonite

Build Status

On release names

Lettuce release names will be inspired by any green stuff.

Barium: In form of "barium nitrate" is commonly used to make green fireworks. Such a good name for a first version :)

What

Lettuce is a BDD tool for python, 100% inspired on cucumber.

Motivation

  1. Cucumber makes Ruby even more sexy. Python needed something like it.
  2. Testing must be funny and easy.
  3. Most python developers code in python, not ruby.
  4. Ruby has Capistrano, Python has Fabric. Ruby has cucumber, Python has lettuce.
  5. I personally don't like mixing many languages in small projects. Keeping all in python is better.
  6. I love python, and ever did. But I also ever missed something that make writing tests easier and funnier.
  7. I like nose, which is a unittest pythonic framework. However, as the project I work on grows, so do the tests, and it becomes harder to understand them.

Documentation

See full documentation on http://lettuce.it/

Dependencies

you will need to install these dependencies in order to hack lettuce :) all them are used within lettuce tests

you could use a virtualenv:

> mkvirtualenv lettuce
> workon lettuce
> pip install -r requirements.txt

note this uses virtualenvwrapper to save some virtualenv handling hassle. you can also use virtualenv the regular way.

or just install manually:

> sudo pip install -r requirements.txt

or do it really from scratch:

  • nose

    [sudo] pip install nose

  • mox

    [sudo] pip install mox

  • sphinx

    [sudo] pip install sphinx

  • lxml

    [sudo] pip install lxml

  • tornado

    [sudo] pip install tornado

  • django

    [sudo] pip install django

mailing list

for users

http://groups.google.com/group/lettuce-users

for developers

http://groups.google.com/group/lettuce-developers

Special thanks

  1. Cucumber crew, for creating such a AWESOME project, and for inspiring Lettuce.
  2. Tatiana for helping a lot with documentation.
  3. Django which documentation structure was borrowed.
  4. Andres Jaan Tack for his awesome contributions
  5. Erlis Vidal for creating a tutorial of how to install lettuce on windows.

Known issues

windows support

erlis have made a awesome job by making lettuce work on windows. He posted here how to install lettuce on windows.

License

<Lettuce - Behaviour Driven Development for python>
Copyright (C) <2010-2020>  Gabriel Falcão <[email protected]>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

lettuce's People

Contributors

adaschevici avatar akaihola avatar algernon avatar alonisser avatar apieum avatar benoitbryon avatar bkabrda avatar chris-morgan avatar danni avatar davidsulc avatar dnozay avatar fsouza avatar gabrielfalcao avatar grahack avatar hltbra avatar hmleal avatar jensrantil avatar kevinastone avatar kyleconroy avatar medwards avatar michelts avatar mitgr81 avatar nikolas avatar pehas avatar pokutnik avatar pshomov avatar rickycook avatar skorokithakis avatar systemparadox avatar wpjunior avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

lettuce's Issues

It should show output as in cucumber

Colored output on shell

Feature description is WHITE
Step currently running is GRAY
Steps that have failed, get RED
Steps that have passed, get GREEN as Lettuce leaves
Steps not yet defined, get YELLOW

Important

It is very useful to show the referenced python file of each step, referencing the line number. Exactly as in Cucumber example

Environment should be easy to set

Environment (setup, teardown and global scope)

** AKA thread-local stuff **

A global python file will be imported, maybe something like:

terrain.py

which contains stuff like:

from lettuce.terrain import before_each_scenario
from lettuce.terrain import after_each_scenario
@before_each_scenario
def populate_database(scenario):
    from my_models import Person
    Person(name="John Doe").save()

@after_each_scenario
def reset_database(scenario):
    from my_models import Person
    Person.delete_all()

And maybe, something that make easy stuff like, creating a single instance of a browser driver.
from lettuce.terrain import world
from webdriver_firefox.webdriver import WebDriver

world.browser = WebDriver()

So that, when and where ever I decide to use the browser driver, I do not need to instantiate it again, just do:

from lettuce.terrain import world
@step(u'I go to google home page')
def browse_google(context):
    world.browser.get("http://google.com")

And so on

bold output strings that match groups

lettuce should identify parts of strings that matches regex groups at step definitions, and output it as bold.

for example:

Given I fill textbox "username" with "gabriel"

and the step definition:

@step('I fill textbox "(.*)" with "(.*)"')
def fill_txtbox(step, name, value):
    pass

it should output like this;

Given I fill textbox "username" with "gabriel"
there is a discussion about it at #3

Step definitions should receive matched groups as params

And must work for both named and unnamed groups.

Example with unnamed groups:

from lettuce import step
@step(r'Given I match this group "(.*)"')
def given_unnamed(group):
    pass

Example with named groups:

from lettuce import step
@step(r'Given I match this group "(?P<foobar>.*)"')
def given_unnamed(foobar):
    pass

Example with both:

from lettuce import step
@step(r'Given I (match|search) this group "(?P<name>.*)"')
def given_unnamed(action, name):
    pass

world should have immutable attributes

If set some unexistent attribute in world, and it starts with _, the it must become immutable
lettuce will use it to store its global stuff:

world._runner
world._shell

Changing them must raise a exception like:
AttributeError('lettuce.world attributes starting with "_" are immutable')

Handle KeyboardInterruption

Lettuce should show the current test results already ran when user does a control-c or something that raises KeyboardInterruption.

It is so cool, developer will be able to cancel the whole feature set to run when some fail

Support for tags

Tagging is cool, I can run scenarios that suit different ocasions

Tagging
Running

Scenario outlines does not work within a feature

Example:

Feature: Do many things at once
    In order to automate tests
    As a automation freaky
    I want to use scenario outlines

    Scenario Outline: Add two numbers
        Given I have entered <input_1> into the calculator
        And I have entered <input_2> into the calculator
        When I press <button>
        Then the result should be <output> on the screen

    Examples:
        | input_1 | input_2 | button | output |
        | 20      | 30      | add    | 50     |
        | 2       | 5       | add    | 7      |
        | 0       | 40      | add    | 40     |

Refactor lettuce.plugins.shell_output and lettuce.plugins.colored_shell_output

Those modules must be refactored to use couleur.

shell_output must print with colored markup, something like:

sys.stdout.write("{red}1 failed")

and shell_output will setup couleur to ignore those markups:

couleur.stdout_filter.setup(ignore_markups=True)

thus colored_shell_output will do:

  1. import shell_output plugin

  2. setup couleur to process stdout markups:

    couleur.stdout_filter.setup(ignore_markups=False)

Can define callbacks to run before and after each feature

It can be defined in any file that will be imported by lettuce.

But lettuce documentation should tell to use it at terrain.py

examples:
from lettuce.terrain import before
from lettuce.terrain import after

@before.each_feature
def populate_database(scenario):
    from my_models import Person
    Person(name="John Doe").save()

@after.each_feature
def reset_database(scenario):
    from my_models import Person
    Person.delete_all()

Can define callbacks to run before and after each scenario

It can be defined in any file that will be imported by lettuce.

But lettuce documentation should tell to use it at terrain.py

examples:
from lettuce.terrain import before
from lettuce.terrain import after

@before.each_scenario
def populate_database(scenario):
    from my_models import Person
    Person(name="John Doe").save()

@after.each_scenario
def reset_database(scenario):
    from my_models import Person
    Person.delete_all()

Unicode error on python setup.py install

pats@patrycjuszszydlo:~/Pulpit/Pobieranie/lettuce$ sudo python setup.py install
running install
running bdist_egg
running egg_info
creating lettuce.egg-info
writing lettuce.egg-info/PKG-INFO
Traceback (most recent call last):
  File "setup.py", line 38, in 
    packages=get_packages()
  File "/usr/lib/python2.5/distutils/core.py", line 151, in setup
    dist.run_commands()
  File "/usr/lib/python2.5/distutils/dist.py", line 974, in run_commands
    self.run_command(cmd)
  File "/usr/lib/python2.5/distutils/dist.py", line 994, in run_command
    cmd_obj.run()
  File "/usr/lib/python2.5/site-packages/setuptools/command/install.py", line 76, in run
    self.do_egg_install()
  File "/usr/lib/python2.5/site-packages/setuptools/command/install.py", line 96, in do_egg_install
    self.run_command('bdist_egg')
  File "/usr/lib/python2.5/distutils/cmd.py", line 333, in run_command
    self.distribution.run_command(command)
  File "/usr/lib/python2.5/distutils/dist.py", line 994, in run_command
    cmd_obj.run()
  File "/usr/lib/python2.5/site-packages/setuptools/command/bdist_egg.py", line 167, in run
    self.run_command("egg_info")
  File "/usr/lib/python2.5/distutils/cmd.py", line 333, in run_command
    self.distribution.run_command(command)
  File "/usr/lib/python2.5/distutils/dist.py", line 994, in run_command
    cmd_obj.run()
  File "/usr/lib/python2.5/site-packages/setuptools/command/egg_info.py", line 170, in run
    writer(self, ep.name, os.path.join(self.egg_info,ep.name))
  File "/usr/lib/python2.5/site-packages/setuptools/command/egg_info.py", line 379, in write_pkg_info
    metadata.write_pkg_info(cmd.egg_info)
  File "/usr/lib/python2.5/distutils/dist.py", line 1076, in write_pkg_info
    self.write_pkg_file(pkg_info)
  File "/usr/lib/python2.5/distutils/dist.py", line 1094, in write_pkg_file
    file.write('Author: %s\n' % self.get_contact() )
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe3' in position 20: ordinal not in range(128)
pats@patrycjuszszydlo:~/Pulpit/Pobieranie/lettuce$

Best regards,
PS

Create a django app within lettuce, to manage lettuce within django :)

In a few words, the programmer will be able to do something like:

settings.py:

...
INSTALLED_APPS = (
    ...
    "lettuce.django"
    ...
)

It will give us:

python manage.py lettuce

that runs lettuce within python, so that we will be able to use django models within lettuce steps:

from lettuce import step
from myapp.models import Poll

@step("Given I have the following polls:")
def have_items(step):
    for poll in step.data_list:
        Poll.objects.create(name=poll['name'])

Lettuce may also put Django's builtin server running at 0.0.0.0:9000, in a thread, so that lettuce users will be able to use browser test tools such as selenium, webdriver, windmill and so on

mailing list?

do you have a mailing list to communicate on yet? or a google groups?

Documentation!

Lettuce should have a awesome documentation, inspired on Django's.

Would be awesome to put the documentation available on github too

Features should have description

They must be parsed from the feature, it must be tested in a full-featured feature, example:

Feature: Do many things at once
    In order to automate tests
    As a automation freaky
    I want to use scenario outlines

    Scenario Outline: Add two numbers
        Given I have entered <input_1> into the calculator
        And I have entered <input_2> into the calculator
        When I press <button>
        Then the result should be <output> on the screen

    Examples:
        | input_1 | input_2 | button | output |
        | 20      | 30      | add    | 50     |
        | 2       | 5       | add    | 7      |
        | 0       | 40      | add    | 40     |

Can't install in Python 2.5

pip install lettuce works correctly on Python 2.6, but doesn't on Python 2.5. Apparently this is due to a known bug in distutils that mishandles unicode strings. In this case, it's your name, Gabriel Falcão, that triggers the problem.

A way to work this around would be explicitly encoding the string as follows:

author=u'Gabriel Falcão'.encode("UTF-8")

Not sure if this has side effects though. Any ideas?

lettuce should find step definitions even without __init__.py file within step_definitions folder

Why ?

It will be a python kick-ass feature.

Mostly python libraries and programs at all have this issue.
It is not a big problem, since it suits python's zen that says: "Explicit is better than implicit"

Althrough, programmers use to forget to create init.py files within dirs, and I've seen so many programmers (specially rookies) loosing half an hour, and even hours debugging after this simple problem.

How to ?

Quite simple:
Lettuce will create a empty init.py file within step_definitions folder under any dir that contains *.feature files.

The init.py file created by lettuce must contain:

# -*- coding: utf-8 -*-
# This file was automatically created by lettuce
# http://github.com/gabrielfalcao/lettuce/

hooks for django

before and after apps:

@before.each_app
def do_something_before(app_module):
    pass

@after.each_app
def do_something_after(app_module):
    pass

before and after the "harvest"

@before.harvest
def do_something_before(dict_of_local_variables):
    pass

@after.harvest
def do_something_after(list_of_results):
    pass

before and after runserver

@before.runserver
def do_something_before(server_instance):
    pass

@after.runserver
def do_something_before(server_instance):)
    pass

threading support

handling request

@before.handle_request
def something_before(httpd):
    pass

@after.handle_request
def something_after(httpd):
    pass

running server

@before.within_runserver
def something_before(thread_instance):
    pass

@after.within_runserver
def something_after(thread_instance):
    pass

Lettuce always try to load a environment file

Lettuce always try to load terrain.py which can be located ONLY in the dir which lettuce runs

Example:
gabriel@durga:~/Projects/my-project$ lettuce features

Will try to import: ~/Projects/my-project/terrain.py

Can define callbacks to run before and after all

It can be defined in any file that will be imported by lettuce.

But lettuce documentation should tell to use it at terrain.py

examples:
from lettuce.terrain import before
from lettuce.terrain import after

@before.all
def populate_database(scenario):
    from my_models import Person
    Person(name="John Doe").save()

@after.all
def reset_database(scenario):
    from my_models import Person
    Person.delete_all()

Self documenting would be AWESOME!

What if at command line I could type something like:

gabriel@durga:~/Projects/my-project$ lettuce harvest
Steps defined here:
    /the client '(.*)' rents '(.*)'/
    Step example:
        "When the client 'John Doe' rents 'Iron man 2"
    Defined At:
        features/step_definitions/movie_rental_steps.py:14

It could be done by simply doing at features/step_definitions/movie_rental_steps.py:
from lettuce import step
@step(r"the client '(.)' rents '(.)'")
def client_rents(self, client, movie):
"When the client 'John Doe' rents 'Iron man 2"
pass

AttributeError: 'thread._local' object has no attribute <attr here>

I have two features. So, before implement the second, the global variable world runs fine. But, when implement the second feature (only add @step(r'desc') def ...) the lettuce raise this exception.

In the first feature I have a attribute world.username. This works fine. Implement the second feature, raise AttributeError: 'thread._local' object has no attribute 'username'

Steps should be aware of its definitions

This ticket is a child of #8

A step must be aware of its definition.

Example:
step.defined_at.file == "/full/path/to/step_definitions/my_steps.py"
steo.defined_at.line == 1

Can define callbacks to run before and after each step

It can be defined in any file that will be imported by lettuce.

But lettuce documentation should tell to use it at terrain.py

examples:
from lettuce.terrain import before
from lettuce.terrain import after

@before.each_step
def populate_database(scenario):
    from my_models import Person
    Person(name="John Doe").save()

@after.each_step
def reset_database(scenario):
    from my_models import Person
    Person.delete_all()

It should be simple to define steps

A python file that has methods with @lettuce.step decorator:

from lettuce import *
@step(u'I have the following tables:')
def have_following_tables(context, dicts):
    assert {"Item": "Value"} in dicts

And assertion errors must be enough to fail steps, as well

Support for step transforms

It allows tranforming matched group strings into any kind of object.
The description at cucumber's wiki is here

Example:

from sure import that
from lettuce import step, transform
from django.contrib.auth.models import User

@transform(r'the user "(.*)"')
def transform_user(username):
    user_object = User.objects.get(username=username)
    return user_object

@step(r'I clone permissions from the user "(.*)" to the user "(.*)"'):
def clone_permissions_from_to(step, one, two):
    assert that(one).is_a(User)
    assert that(two).is_a(User)

    two.clone_permissions_from(one)

Language error

Here is my languages.py code - http://pastebin.com/k7FEnkCL

Example scenario

language: pl

Właściwość: Wyszukiwanie

Scenariusz: Znajdywanie wpisów, wydarzeń, miejsc, grup i filmów o cesarskim cięciu
Zakładając że jestem na stronie głównej
Jeżeli wpisze w wyszukiwarke: "cesarskie ciecie"
Wtedy otrzymam "20" ostatnich wpisów, wydarzeń, miejsc, grup, filmów zawierających frazę: "cesarskie cięcie"

And exception

tests$ lettuce

Traceback (most recent call last):
File "/usr/bin/lettuce", line 5, in
pkg_resources.run_script('lettuce==0.1rc12', 'lettuce')
File "/usr/lib/python2.5/site-packages/pkg_resources.py", line 448, in run_script
self.require(requires)[0].run_script(script_name, ns)
File "/usr/lib/python2.5/site-packages/pkg_resources.py", line 1166, in run_script
execfile(script_filename, namespace, namespace)
File "/usr/lib/python2.5/site-packages/lettuce-0.1rc12-py2.5.egg/EGG-INFO/scripts/lettuce", line 53, in
main()
File "/usr/lib/python2.5/site-packages/lettuce-0.1rc12-py2.5.egg/EGG-INFO/scripts/lettuce", line 48, in main
result = runner.run()
File "/usr/lib/python2.5/site-packages/lettuce-0.1rc12-py2.5.egg/lettuce/init.py", line 109, in run
results.append(feature.run())
File "/usr/lib/python2.5/site-packages/lettuce-0.1rc12-py2.5.egg/lettuce/core.py", line 706, in run
callback(self)
File "/usr/lib/python2.5/site-packages/lettuce-0.1rc12-py2.5.egg/lettuce/plugins/colored_shell_output.py", line 154, in print_feature_running
write_out("\033[1;37m%s\n" % line)
File "/usr/lib/python2.5/site-packages/lettuce-0.1rc12-py2.5.egg/lettuce/plugins/colored_shell_output.py", line 47, in write_out
wrt(wp(what))
File "/usr/lib/python2.5/site-packages/lettuce-0.1rc12-py2.5.egg/lettuce/plugins/colored_shell_output.py", line 26, in wrt
sys.stdout.write(what)
UnicodeEncodeError: 'ascii' codec can't encode character u'\u0142' in position 8: ordinal not in range(128)

Best regards,
PS

Features, Scenarios and Steps must know about its definitions

Features, Scenarios and Steps must know the file path and line numbers that implement them.

Features:
feature.described_at.file == "/full/path/to/definition.feature"
feature.described_at.line == 17

Scenarios:
scenario.described_at.file == "/full/path/to/definition.feature"
scenario.described_at.line == 30

Step:
step.described_at.file == "/full/path/to/definition.feature"
steo.described_at.line == 25
step.defined_at.file == "step_definitions/my_steps.py"
steo.defined_at.line == 2

Can define callbacks to run before and after all

It can be defined in any file that will be imported by lettuce.

But lettuce documentation should tell to use it at terrain.py

examples:
from lettuce.terrain import before
from lettuce.terrain import after

@before.all
def populate_database(scenario):
    from my_models import Person
    Person(name="John Doe").save()

@after.all
def reset_database(scenario):
    from my_models import Person
    Person.delete_all()

Mode to print a summary like the following:

Mode to print a summary like the following:
"passed X tests out of Y" (if all pass) - exiting with the return code 0
if a test fails:
"passed X tests out of Y, test Z failed" - exiting with return code 1
if multiple tests fail:
"passed X tests out of Y, tests Z,P failed" - exiting with return code 1

The output needs to be on one line - this is required for use in nagios.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.