Showing posts with label python. Show all posts
Showing posts with label python. Show all posts

Friday, 16 May 2014

From a PIE to an API !!

Last week we were pretty much concerned about what to use and what not ?
and what changes we shall introduce in our model of Testing ?

So may be if you have curiosity about what we used and what we decided, This post is for you !

Overall Scenario last week: We wanted to use FactoryBoy for database object modelling and reliable data for tests.
So using FactoryBoy meant that we had to keep our Functional Tests with the application itself.
This was the change we decided to have and pretty much kicked of the work and initialized the test objects in application repository.

So what next ?
In our old testing model we ran the Functional tests on staging/production application already running. So now the challenge was:
How will we trigger the server ?

One of the solution which instantly came to mind was using LiveServerTestCase 
So things were *almost* finalized !!

But things come to mind as we start working, and this time it was not something which could be ignored.
Man, we would not be able to run the tests on Staging and Production or in general any other remotely hosted clone of OneAndDone, Also running the tests locally would mean setting up of a local instance of OneAndDone. This was what came to mind as soon as I began writing the first test and it was for sure not what we wanted, because  of mainly two reasons:

  1. Why will a contributor developing a test case want to set up the application locally ? We definitely don't want to assume our contributors to be Application developers. So this was a hindrance for contributors.
  2. We wanted to run the tests on staging and production because it gives us a better idea of current state of Application.

So we decided to give it a rethought.

After many discussions with other team members it settled down to two options:
  1. Keep the tests local for better data population and faster test runs.
  2. Have the tests in a separate repository making it easy for contributors to work on and to make us able to run the tests on stage/prod.

Finally we decided to go with the second one because of the above mentioned limitations of first, or the benefits of second overpowered the benefits of first. We realized our current model to be more advance than most of the other methods discovered.

The main changes we decided to have in these tests that make them better and advance than the tests for most of the other Web QA projects are:

  • Develop and Use a REST API which interacts with database objects remotely. So it helps us to create/delete the test data. For developing this API we decided to use Django REST framework over tastypie for some reasons based on prior experiences of developers.
  • We decided to use pytest fixtures instead of SetUp and TearDown methods which will allow creation/deletion of mock objects using the REST API.

We again kicked off the work by initializing the Page Objects and Base Class and opened some Test Case bugs.
Now I am looking forward to developing the REST API and start writing the tests next week.

Sunday, 23 February 2014

Factory Boy !

This Post we are gonna talk about FactoryBoy, Although the original documentation on FactoryBoy website is very good, short and precise , but still here are some quick notes which would get you started and for any Reference would be much useful.

So What is FactoryBoy ?

FactoryBoy provides a default way of getting new Instances,while still being able to override some fields on per-call basis.

Advantages ?

  1. Particularly useful in handling situations which require creation of object, interacting with database, it provides safe/better way for data population and instance creation.
  2. Provides support for multiple build strategies (saved/unsaved, attribute dicts, stubbed objects)
  3. Powerful helpers (sequence, sub-factories, reverse dependencies), which we are going to talk about later in this post.

Let's start with an example:

We have a model object Poll which has
  • A polling question
  • Date on which Poll is published
  • A function to check if the poll was published recently

To tests such kind of an object we can create tests like
  • Create a poll with future publishing date and check if it was published recently
  • Create a poll with past publishing date and check if it was published recently
  • Create a poll with recent publishing date and check if it was published recently

This test could be easily modified to use factories like:
Define factory classes to make instances in factories.py like:

As in above example factories declare a set of attributes used to instantiate an object, whose class is defined
in FACTORY_FOR attribute.
A given class might be associated to many factory subclasses by having different default values for attributes in Factory class example
A User class might be related to Userfactory(), FemaleUserFactory(), MaleUserFactory()
each having different value for the gender attribute.

Now after creating a factory we can modify our tests to use the factory class to instantiate a new object like

As is visible it is possible to override the default values for attributes in factory class by passing new values for these attributes example
Value for pub_date is passed in this case to create a post with past date.

Some of the helper functions come handy with factory class are:

Sequence declaration:

When a field has a unique key its value must be different, thus these unique values can generated like
username = factory.Sequence(lambda n: 'user%d' % n)

Lazy Attribute:

For fields deduced from other fields like
username = factory.Sequence(lambda n: 'user%d' % n)
email = factory.LazyAttribute(lambda obj: '%s@example.com' % obj.username)
Here email is deduced from username

Inheritance:

Same as normal inheritance, we can override attributes for parent class

Non-kwarg arguments:

Some classes take a few, non-kwarg arguments first.

Strategies:

Factories support two built-in strategies
MyFactory.create() provide a local object and saves it to database
MyFactory.build() provide a local object


Database dependency issues:

Dependent objects(Foreign keys):

first_name = factory.Sequence(lambda n: "Agent %03d" % n)
group = factory.SubFactory(GroupFactory)
Here the group attribute is a foreign key for user table and thus it becomes a SubFactory in factory class.

Other such issues like

Reverse Dependencies(Reverse Foreign Keys)

When a related object should be created upon object creation

Simple ManytoMany

Building the adequate link between two models depends heavily on the use case

ManytoMany with a 'through'

do exists. Examples for which can be found here

Fuzzy Attributes:

These are used to create random data for various datatypes and also while creating this data we can specify some limits so that we can generate it according to our needs. example
fi = FuzzyInteger(0, 42)
fdt = FuzzyDateTime(datetime.datetime(2008, 1, 1, tzinfo=UTC))

Thus this is a very quick introduction to FactoryBoy, which makes it clear what is it used for and how to use it.

There are many other attributes, functions, and strategies which are discussed in detailed documentation with some very good examples to get a deep insight.