def handles_stoptest_exceptions(self): ''' if stop test exception is thrown stop executing instructions ''' mock_fn = lancelot.MockSpec(name='mock_fn') mock_call = lancelot.MockSpec(name='mock_call') results = lancelot.MockSpec(name='results') a_list = [['id_', 'call', 'instance', 'fn', 'arg'], ['id_', 'call', 'instance2', 'fn2', 'arg2']] instructions = Instructions(a_list, lambda item: mock_fn.instruction_for(item)) spec = lancelot.Spec(instructions) ctx = ExecutionContext() msg = "I couldn't eat another thing. I'm absolutely stuffed." # Suppress warning log message that we know will be generated logger = logging.getLogger('Instructions') log_level = logger.getEffectiveLevel() logger.setLevel(logging.ERROR) try: spec.execute(ctx, results).should_collaborate_with( mock_fn.instruction_for(a_list[0]).will_return(mock_call), mock_call.execute(ctx, results).will_raise(StopTestException(msg)), results.failed(mock_call, msg, True)) finally: # Put logger back to how it was logger.setLevel(log_level) ctx.cleanup_imports()
def handles_stoptest_exceptions(self): ''' if stop test exception is thrown stop executing instructions ''' mock_fn = lancelot.MockSpec(name='mock_fn') mock_call = lancelot.MockSpec(name='mock_call') results = lancelot.MockSpec(name='results') a_list = [ ['id_', 'call', 'instance', 'fn', 'arg'], ['id_', 'call', 'instance2', 'fn2', 'arg2'] ] instructions = Instructions(a_list, lambda item: mock_fn.instruction_for(item)) spec = lancelot.Spec(instructions) ctx = ExecutionContext() msg = "I couldn't eat another thing. I'm absolutely stuffed." # Suppress warning log message that we know will be generated logger = logging.getLogger('Instructions') log_level = logger.getEffectiveLevel() logger.setLevel(logging.ERROR) try: spec.execute(ctx, results).should_collaborate_with( mock_fn.instruction_for(a_list[0]).will_return(mock_call), mock_call.execute(ctx, results).will_raise(StopTestException(msg)), results.failed(mock_call, msg, True) ) finally: # Put logger back to how it was logger.setLevel(log_level) ctx.cleanup_imports()
def handles_builtins(self): ''' get_type() should handle builtin types and get_module() should not affect sys.modules when module was already loaded, e.g. builtins''' context = ExecutionContext() spec = lancelot.Spec(context) spec.get_type('builtins.dict').should_be(dict) spec.get_type('builtins.str').should_be(str) spec.get_module('builtins').should_be(SameAs(sys.modules['builtins'])) context.cleanup_imports()
def handles_builtins(self): ''' get_type() should handle builtin types and get_module() should not affect sys.modules when module was already loaded, e.g. __builtin__''' context = ExecutionContext() spec = lancelot.Spec(context) spec.get_type('__builtin__.dict').should_be(dict) spec.get_type('__builtin__.str').should_be(str) spec.get_module('__builtin__').should_be(SameAs(sys.modules['__builtin__'])) context.cleanup_imports()
def cleansup_sys_modules(self): ''' cleanup_imports() should not choke on module that were imported but are no longer in sys.modules ''' execution_context = ExecutionContext() path = self._nonsrc_path(execution_context) execution_context.add_import_path(path) execution_context.get_module('import_me') spec = lancelot.Spec(execution_context) del(sys.modules['import_me']) spec.cleanup_imports().should_not_raise(Exception)
def raises_exceptions(self): ''' Requesting a non-existent module should raise ImportError. Requesting a non-existent type should raise TypeError.''' context = ExecutionContext() spec = lancelot.Spec(context) spec.get_module('no.such.module').should_raise(ImportError) spec.get_type('no.such.module.Type').should_raise(ImportError) spec.get_type('NoSuchType').should_raise(TypeError) spec.get_type('waferslim.Mint').should_raise(TypeError) context.cleanup_imports()
def log_handles_unrepresentable_objects(self): ''' Bug #537032: repr(bad_object) when logging is fatal''' class Unrepresentable(object): def __repr__(self): return self._noSuchAttribute level = logging.getLogger('Execution').level try: logging.getLogger('Execution').setLevel(logging.ERROR) ctx = ExecutionContext() ctx.store_instance('ugh', Unrepresentable()) finally: logging.getLogger('Execution').setLevel(level)
def uses_added_type_context(self): ''' add_type_context() should allow classes to be found without fully-dot-qualified prefixes''' ctx = ExecutionContext() test_case_type = ctx.get_type('unittest.TestCase') spec = lancelot.Spec(ctx) spec.get_type('TestCase').should_raise(TypeError) spec.when(spec.add_type_prefix('unittest')) spec.then(spec.get_type('TestCase')).should_not_raise(TypeError) spec.then(spec.get_type('TestCase')).should_be(test_case_type) ctx.cleanup_imports()
def log_handles_unrepresentable_objects(self): ''' Bug #537032: repr(bad_object) when logging is fatal''' class Unrepresentable: def __repr__(self): return self._noSuchAttribute level = logging.getLogger('Execution').level try: logging.getLogger('Execution').setLevel(logging.ERROR) ctx = ExecutionContext() ctx.store_instance('ugh', Unrepresentable()) finally: logging.getLogger('Execution').setLevel(level)
def uses_added_import_paths(self): ''' add_import_path() should allow packages or modules to be found without altering sys.path''' execution_context = ExecutionContext() spec = lancelot.Spec(execution_context) spec.get_module('import_me').should_raise(ImportError) path = self._nonsrc_path(execution_context) spec.when(spec.add_import_path(path)) spec.then(spec.get_module('import_me')).should_not_raise(ImportError) lancelot.Spec(sys.path).it().should_not_contain(path) execution_context.cleanup_imports()
def stores_instance(self): ''' store_instance(name, value) should put the name,value pair in the instances dict where it can be retrieved by get_instance(name). instances should be isolated across execution contexts''' context = ExecutionContext() spec = lancelot.Spec(context) spec.get_instance('wafer thin').should_be(None) spec.when(spec.store_instance('wafer thin', 'mint')) spec.then(spec.get_instance('wafer thin')).should_be('mint') spec = lancelot.Spec(ExecutionContext()) spec.get_instance('wafer thin').should_be(None) context.cleanup_imports()
def decision_table(): ''' Simulate the invocation of the example decision table. Note that the standard slim table() / execute() / reset() steps are missing from this simplistic sequence ''' execution_context = ExecutionContext() results = Results() instr_list = [ ['1', 'import', 'waferslim.examples.decision_table'], ['2', 'make', 'table', 'ShouldIBuyMilk'], ['3', 'call', 'table', 'setCashInWallet', '10'], ['4', 'call', 'table', 'setCreditCard', 'yes'], ['5', 'call', 'table', 'setPintsOfMilkRemaining', '1'], [ '6', 'call', 'table', 'goToStore', ], ] Instructions(instr_list).execute(execution_context, results) spec = lancelot.Spec(results.collection()) spec.it().should_contain(['1', 'OK']) spec.it().should_contain(['2', 'OK']) spec.it().should_contain(['3', '/__VOID__/']) spec.it().should_contain(['4', '/__VOID__/']) spec.it().should_contain(['5', '/__VOID__/']) spec.it().should_contain(['6', 'no'])
def uses_added_type_context(self): ''' add_type_context() should allow classes to be found without fully-dot-qualified prefixes. A unicode param may be passed.''' ctx = ExecutionContext() test_case_type = ctx.get_type('unittest.TestCase') spec = lancelot.Spec(ctx) spec.get_type('TestCase').should_raise(TypeError) spec.when(spec.add_type_prefix('unittest')) spec.then(spec.get_type('TestCase')).should_not_raise(TypeError) spec.then(spec.get_type('TestCase')).should_be(test_case_type) second_ctx = ExecutionContext() spec = lancelot.Spec(second_ctx) spec.when(spec.add_type_prefix(u'waferslim.examples.decision_table')) spec.then(spec.get_type(u'ShouldIBuyMilk')).should_not_raise(TypeError) ctx.cleanup_imports()
def imports_twisted(self): ''' Bug #497245: cannot import twisted ''' from os.path import join, exists for location in sys.path: pkg = join(location, join('twisted', '__init__.py')) if exists(pkg) \ or exists(pkg + 'c') \ or exists(pkg + 'o'): twisted_found = True break lancelot.Spec(twisted_found).it().should_be(True) context = ExecutionContext(isolate_imports=False) #TODO: isolated?! context.add_import_path(self._nonsrc_path(context)) spec = lancelot.Spec(context) spec.get_module('import_twisted').should_be(Type(types.ModuleType)) spec.get_module('twisted').should_be(Type(types.ModuleType)) context.cleanup_imports()
def loops_through_list(self): ''' Instructions should collaborate with instruction_for to instantiate a list of instructions, which execute() loops through ''' mock_fn = lancelot.MockSpec(name='mock_fn') mock_make = lancelot.MockSpec(name='mock_make') mock_call = lancelot.MockSpec(name='mock_call') a_list = [['id_0', 'make', 'instance', 'fixture', 'argument'], ['id_1', 'call', 'instance', 'f', '3']] instructions = Instructions(a_list, lambda item: mock_fn.instruction_for(item)) spec = lancelot.Spec(instructions) ctx = ExecutionContext() results = Results() spec.execute(ctx, results).should_collaborate_with( mock_fn.instruction_for(a_list[0]).will_return(mock_make), mock_make.execute(ctx, results), mock_fn.instruction_for(a_list[1]).will_return(mock_call), mock_call.execute(ctx, results)) ctx.cleanup_imports()
def get_type_all_lowercaps(self): ''' get_type(namewithoutspaces) => get_type (Namewithoutspaces) ''' context = ExecutionContext() context.add_type_prefix('waferslim.examples.helper_fixtures') multiplication = context.get_type('Multiplication') spec = lancelot.Spec(context) spec.get_type('multiplication').should_be(multiplication) context.cleanup_imports()
def stores_libraries(self): ''' store_instance(library, value) should put the value with the libraries where it can be retrieved by get_library_method(name). libraries should be isolated across execution contexts''' mr_death = ExecutionContextBehaviour.DeathKnocksAtTheDoor() context = ExecutionContext() spec = lancelot.Spec(context) spec.get_library_method('do_come_in_mr_death').should_be(None) spec.get_library_method('doComeInMrDeath').should_be(None) context.store_instance('libraryXYZ', mr_death) spec = lancelot.Spec(context) spec.get_library_method('do_come_in_mr_death').should_be(mr_death.do_come_in_mr_death) spec.get_library_method('doComeInMrDeath').should_be(mr_death.do_come_in_mr_death) spec = lancelot.Spec(ExecutionContext()) spec.get_library_method('do_come_in_mr_death').should_be(None) spec.get_library_method('doComeInMrDeath').should_be(None) context.cleanup_imports()
def loops_through_list(self): ''' Instructions should collaborate with instruction_for to instantiate a list of instructions, which execute() loops through ''' mock_fn = lancelot.MockSpec(name='mock_fn') mock_make = lancelot.MockSpec(name='mock_make') mock_call = lancelot.MockSpec(name='mock_call') a_list = [ ['id_0', 'make', 'instance', 'fixture', 'argument'], ['id_1', 'call', 'instance', 'f', '3'] ] instructions = Instructions(a_list, lambda item: mock_fn.instruction_for(item)) spec = lancelot.Spec(instructions) ctx = ExecutionContext() results = Results() spec.execute(ctx, results).should_collaborate_with( mock_fn.instruction_for(a_list[0]).will_return(mock_make), mock_make.execute(ctx, results), mock_fn.instruction_for(a_list[1]).will_return(mock_call), mock_call.execute(ctx, results) ) ctx.cleanup_imports()
def warns_if_library_methods_may_pollute_tests(self): ''' libraries with method names "execute" and "reset" may pollute test results, since those methods are called for each row in a decision table ''' polluting_names = ['execute', 'reset', 'table'] for name in polluting_names: logger = lancelot.MockSpec(name='logger') context = ExecutionContext(logger=logger) library = ClassWithNoArgs() setattr(library, name, lambda: None) spec = lancelot.Spec(context) spec.store_instance('library', library).should_collaborate_with( logger.debug(Anything()), logger.warning(Contain('%s()' % name)))
def gets_library_methods_from_fifo_stack(self): ''' Library methods should be retrieved from a fifo stack ''' class GrimReaperKnocks(ExecutionContextBehaviour.DeathKnocksAtTheDoor): def do_come_in_mr_death(self): return "I'm afraid we don't have any beer" context = ExecutionContext() mr_death = ExecutionContextBehaviour.DeathKnocksAtTheDoor() reaper = GrimReaperKnocks() context.store_instance('library1', mr_death) context.store_instance('library2', reaper) spec = lancelot.Spec(context) spec.get_library_method('do_come_in_mr_death').should_be(reaper.do_come_in_mr_death) context.store_instance('library2', mr_death) spec = lancelot.Spec(context) spec.get_library_method('do_come_in_mr_death').should_be(mr_death.do_come_in_mr_death) spec.get_library_method('doComeInMrDeath').should_be(mr_death.do_come_in_mr_death) context.cleanup_imports()
def gets_library_methods_from_fifo_stack(self): ''' Library methods should be retrieved from a fifo stack ''' class GrimReaperKnocks(ExecutionContextBehaviour.DeathKnocksAtTheDoor): def do_come_in_mr_death(self): return "I'm afraid we don't have any beer" context = ExecutionContext() mr_death = ExecutionContextBehaviour.DeathKnocksAtTheDoor() reaper = GrimReaperKnocks() context.store_instance('library1', mr_death) context.store_instance('library2', reaper) spec = lancelot.Spec(context) spec.get_library_method('do_come_in_mr_death').should_be( reaper.do_come_in_mr_death) context.store_instance('library2', mr_death) spec = lancelot.Spec(context) spec.get_library_method('do_come_in_mr_death').should_be( mr_death.do_come_in_mr_death) spec.get_library_method('doComeInMrDeath').should_be( mr_death.do_come_in_mr_death) context.cleanup_imports()
def cleansup_sys_modules(self): ''' cleanup_imports() should not choke on module that were imported but are no longer in sys.modules ''' execution_context = ExecutionContext() path = self._nonsrc_path(execution_context) execution_context.add_import_path(path) execution_context.get_module('import_me') spec = lancelot.Spec(execution_context) del (sys.modules['import_me']) spec.cleanup_imports().should_not_raise(Exception)
def stores_symbol(self): ''' store_symbol(name, value) should put the name,value pair in the symbols dict where it can be retrieved by get_symbol(name). symbols should be isolated across execution contexts. If a symbol is undefined then the value returned is the name of the symbol prefixed with $ -- Bug #537020''' ctx1 = ExecutionContext() spec = lancelot.Spec(ctx1) spec.get_symbol('another_bucket').should_be('$another_bucket') spec.when(spec.store_symbol('another_bucket', 'for monsieur')) spec.then(spec.get_symbol('another_bucket')).should_be('for monsieur') ctx2 = ExecutionContext() spec = lancelot.Spec(ctx2) spec.get_symbol('another_bucket').should_be('$another_bucket') ctx1.cleanup_imports() ctx2.cleanup_imports()
def table_table(): ''' Simulate the invocation of the example "table" table. ''' execution_context = ExecutionContext() results = Results() instr_list = [ ['1', 'import', 'waferslim.examples.table_table'], ['2', 'make', 'tableTable_1', 'Bowling'], [ '3', 'call', 'tableTable_1', 'doTable', [[ '3', '5', '4', '/', 'X', '', 'X', '', '3', '4', '6', '/', '7', '2', '3', '4', '9', '-', '4', '/', '3' ], [ '', '8', '', '28', '', '51', '', '68', '', '75', '', '92', '', '101', '', '108', '', '117', '', '', '130' ]] ], ] Instructions(instr_list).execute(execution_context, results) spec = lancelot.Spec(results.collection()) spec.it().should_contain(['1', 'OK']) spec.it().should_contain(['2', 'OK']) spec.it().should_contain(['3', lancelot.comparators.Type(list)]) # 3rd result, 2nd item is list with query results spec = lancelot.Spec(results.collection()[2][1]) spec.it().should_be(lancelot.comparators.Type(list)) spec.__len__().should_be(2) # list, len 2 # 3rd result, 2nd item, 1st item is list with 1st "row" from results spec = lancelot.Spec(results.collection()[2][1][0]) spec.it().should_be(lancelot.comparators.Type(list)) spec.it().should_be([ TableTableConstants.cell_no_change() for cell in results.collection()[2][1][0] ]) # 3rd result, 2nd item, 2ndt item is list with 2nd "row" from results spec = lancelot.Spec(results.collection()[2][1][1]) spec.it().should_be(lancelot.comparators.Type(list)) spec.it().should_not_be([ TableTableConstants.cell_no_change() for cell in results.collection()[2][1][1] ])
def script_table(): ''' Simulate the invocation of the example script table. ''' execution_context = ExecutionContext() results = Results() instr_list = [ ['1', 'import', 'waferslim.examples.script_table'], ['2', 'make', 'table', 'LoginDialogDriver', 'wafer', 'slim'], ['3', 'call', 'table', 'loginWithUsernameAndPassword', \ 'wafer', 'thin' ], ['4', 'call', 'table', 'loginMessage', ], ['5', 'call', 'table', 'numberOfLoginAttempts', ], ] Instructions(instr_list).execute(execution_context, results) spec = lancelot.Spec(results.collection()) spec.it().should_contain(['1', 'OK']) spec.it().should_contain(['2', 'OK']) spec.it().should_contain(['3', 'false']) spec.it().should_contain(['4', 'wafer not logged in.']) spec.it().should_contain(['5', '1'])
def symbols(): ''' Simulate the invocation of the decision table that uses symbols. Note that the standard slim table() / execute() / reset() steps are missing from this simplistic sequence ''' execution_context = ExecutionContext() results = Results() instr_list = [ ['1', 'import', 'waferslim.examples.values_and_symbols'], ['2', 'make', 'table', 'SomeDecisionTable'], ['3', 'call', 'table', 'setInput', '3'], ['4', 'callAndAssign', 'V', 'table', 'output'], ['5', 'call', 'table', 'setInput', '$V'], ['6', 'call', 'table', 'output'], ] Instructions(instr_list).execute(execution_context, results) spec = lancelot.Spec(results.collection()) spec.it().should_contain(['1', 'OK']) spec.it().should_contain(['2', 'OK']) spec.it().should_contain(['3', '/__VOID__/']) spec.it().should_contain(['4', '4']) spec.it().should_contain(['5', '/__VOID__/']) spec.it().should_contain(['6', '8'])
def target_for_tries_pythonic_conversion(self): ''' target_for() should look first for a pythonic method name and if that is not found then look for the original method name ''' method_name = 'aMethod' class ClassWithAMethod: def a_method(self): pass instance = ClassWithAMethod() context = ExecutionContext() spec = lancelot.Spec(context) spec.target_for(instance, method_name).should_be(instance.a_method) class ClassWithACamelCaseMethod: def aMethod(self): pass instance = ClassWithACamelCaseMethod() spec = lancelot.Spec(context) spec.target_for(instance, method_name).should_be(instance.aMethod)
def stores_libraries(self): ''' store_instance(library, value) should put the value with the libraries where it can be retrieved by get_library_method(name). libraries should be isolated across execution contexts''' mr_death = ExecutionContextBehaviour.DeathKnocksAtTheDoor() context = ExecutionContext() spec = lancelot.Spec(context) spec.get_library_method('do_come_in_mr_death').should_be(None) spec.get_library_method('doComeInMrDeath').should_be(None) context.store_instance('libraryXYZ', mr_death) spec = lancelot.Spec(context) spec.get_library_method('do_come_in_mr_death').should_be( mr_death.do_come_in_mr_death) spec.get_library_method('doComeInMrDeath').should_be( mr_death.do_come_in_mr_death) spec = lancelot.Spec(ExecutionContext()) spec.get_library_method('do_come_in_mr_death').should_be(None) spec.get_library_method('doComeInMrDeath').should_be(None) context.cleanup_imports()
def query_table(): ''' Simulate the invocation of the example query table. Note that the standard slim table() step is missing from this simplistic sequence ''' execution_context = ExecutionContext() results = Results() instr_list = [ ['1', 'import', 'waferslim.examples.query_table'], ['2', 'make', 'table', 'EmployeesHiredBefore', '1999-12-12'], [ '3', 'call', 'table', 'query', ], ] Instructions(instr_list).execute(execution_context, results) spec = lancelot.Spec(results.collection()) spec.it().should_contain(['1', 'OK']) spec.it().should_contain(['2', 'OK']) spec.it().should_contain(['3', lancelot.comparators.Type(list)]) # 3rd result, 2nd item is list with query results spec = lancelot.Spec(results.collection()[2][1]) spec.it().should_be(lancelot.comparators.Type(list)) spec.__len__().should_be(2) # list, len 2 # 3rd result, 2nd item, 1st item is list with one "row" from query spec = lancelot.Spec(results.collection()[2][1][0]) spec.it().should_be(lancelot.comparators.Type(list)) spec.__len__().should_be(4) # list, len 4 spec.it().should_contain( ['employee number', lancelot.comparators.Type(str)]) spec.it().should_contain(['first name', lancelot.comparators.Type(str)]) spec.it().should_contain(['last name', lancelot.comparators.Type(str)]) spec.it().should_contain(['hire date', lancelot.comparators.Type(str)])
def get_unisolated_module_type(self): ''' get_type() should return a requested module type, given the fully qualified name including module. The same type should be returned on successive invocations. The same type should also be returned from different contexts. State in a module should not be isolated within each context''' _types = {'StateAlteringClass':'module_with_state'} execution_context = ExecutionContext(isolate_imports=False) execution_context.add_import_path(self._nonsrc_path(execution_context)) for _type, mod in _types.items(): fully_qualified_name = '%s.%s' % (mod, _type) same_type = execution_context.get_type(fully_qualified_name) lancelot.Spec(same_type.__name__).it().should_be(_type) spec = lancelot.Spec(execution_context) spec.get_type(fully_qualified_name).should_be(SameAs(same_type)) other_context = ExecutionContext(isolate_imports=False) other_context.add_import_path(self._nonsrc_path(other_context)) different_type = other_context.get_type(fully_qualified_name) spec.get_type(fully_qualified_name).should_be( SameAs(different_type)) instances = same_type(), different_type() spec = lancelot.Spec(instances[0]) spec.when(spec.alter_state()) spec.then(spec.get_state()).should_contain(1) spec.then(instances[1].get_state).should_contain(1) execution_context.cleanup_imports() other_context.cleanup_imports()
def get_unisolated_imported_module(self): ''' get_module() should return a requested module, which should remain in sys.modules as it has been loaded unisolated. The same module should be returned on successive invocations. The same module should be returned from different contexts ''' same_context = ExecutionContext() same_context.add_import_path(self._nonsrc_path(same_context)) different_context = ExecutionContext(isolate_imports=False) different_context.add_import_path(self._nonsrc_path(different_context)) for mod in ('import_me', 'module_with_state'): spec = lancelot.Spec(same_context) spec.get_module(mod).should_be(Type(types.ModuleType)) same_module = same_context.get_module(mod) spec.get_module(mod).should_be(SameAs(same_module)) sys_spec = lancelot.Spec(sys.modules) sys_spec.it().should_contain(mod) different_module = different_context.get_module(mod) spec.get_module(mod).should_be(SameAs(different_module)) same_context.cleanup_imports() different_context.cleanup_imports()
def get_unisolated_module_type(self): ''' get_type() should return a requested module type, given the fully qualified name including module. The same type should be returned on successive invocations. The same type should also be returned from different contexts. State in a module should not be isolated within each context''' _types = {'StateAlteringClass': 'module_with_state'} execution_context = ExecutionContext(isolate_imports=False) execution_context.add_import_path(self._nonsrc_path(execution_context)) for _type, mod in _types.items(): fully_qualified_name = '%s.%s' % (mod, _type) same_type = execution_context.get_type(fully_qualified_name) lancelot.Spec(same_type.__name__).it().should_be(_type) spec = lancelot.Spec(execution_context) spec.get_type(fully_qualified_name).should_be(SameAs(same_type)) other_context = ExecutionContext(isolate_imports=False) other_context.add_import_path(self._nonsrc_path(other_context)) different_type = other_context.get_type(fully_qualified_name) spec.get_type(fully_qualified_name).should_be( SameAs(different_type)) instances = same_type(), different_type() spec = lancelot.Spec(instances[0]) spec.when(spec.alter_state()) spec.then(spec.get_state()).should_contain(1) spec.then(instances[1].get_state).should_contain(1) execution_context.cleanup_imports() other_context.cleanup_imports()
def stores_symbol_as_str(self): ''' store_symbol(name, value) should store the value as a str ''' spec = lancelot.Spec(ExecutionContext()) spec.when(spec.store_symbol('id', 1)) spec.then(spec.get_symbol('id')).should_be('1')