How to create Test cases in python? - python

I am wrote application in python and I need to write test for app, I want to create some test, which will use inside my application, how can I do this?
I am new in Python and I want to know some automation test to use.
I have this code in main.py, this is a login function
"loginBtn", which is located in LoginWindow, I want to test this function for my application, how can I do this?
class LoginWindow(Screen):
email = ObjectProperty(None)
password = ObjectProperty(None)
def loginBtn(self):
if db.validate(self.email.text, self.password.text):
ProfileWindow.current = self.email.text
self.reset()
sm.current = "main"
else:
invalidLogin()

Related

Python kivy, how to use __init__ for classes with screen manager?

I want to get instances of the attributes in each class, such as the users password and email, but I also want to be able to get the add_widget to come up with only the name, yet:
Here is my code so far
from kivy.uix import Screen, ScreenManager
class WindowManager(ScreenManager):
pass
sm = WindowManager()
In login window
class LoginWindow(Popups, Screen, FloatLayout, BoxLayout):
def __init__(self, email, password, checkBox, **kwargs):
self.email = email
self.password = password
self.checkBox = checkBox
super(self, **kwargs).__init__()
self.name = "login"
And in main app window
sm.add_widget(LoginWindow(name="login"))
#actual phone app class
class PhoneAssistantApp(App):
def __init__(self):
super(self).__init__()
def build(self):
if LoginWindow.checkBox == True:
sm.current = "main"
else:
sm.current = "login" #user sent to login page whenever program is ran
return sm
if __name__ == "__main__":
PhoneAssistantApp().run()
But it comes up with error:
line 352, in <module>
sm.add_widget(LoginWindow(name="login"))
TypeError: __init__() missing 3 required positional arguments: 'email', 'password', and 'checkBox'
My login window in my kv file is simply:
<LoginWindow>:
name: "login" #name used to know where to send
email: email #links to object property in py file class
password: password #links to object property in py file class
checkBox: checkBox #links to boolean property in py file class
I believe the error is in my main program, as I'm trying to figure out how to fit both the attributes instances in with the kivy.
First I had my sm.add_widget and classes names in the App class, like
class PhoneAssistantApp(App):
def __init__(self, **kwargs):
super(self, **kwargs).__init__()
self.screens = ((LoginWindow(name="login"), CreateAccountWindow(name="Create))
self.sm = ScreenManager()
def build(self):
for screen in self.screens:
self.sm.add_widget(screens)
if LoginWindow.checkBox == True:
self.sm.current = "main"
else:
self.sm.current = "login" #user sent to login page whenever program is ran
return self.sm
if __name__ == "__main__":
PhoneAssistantApp().run()
And
class PhoneAssistantApp(App):
def __init__(self, **kwargs):
super(self, **kwargs).__init__()
self.screens = ((LoginWindow(name="login"), CreateAccountWindow(name="Create))
def build(self):
for screen in self.screens:
sm.add_widget(screens)
if LoginWindow.checkBox == True:
sm.current = "main"
else:
sm.current = "login" #user sent to login page whenever program is ran
return sm
if __name__ == "__main__":
PhoneAssistantApp().run()
Yet taking it away didn't get rid of the problem. In addition, getting rid of the **kwargs likely didn't help much either.
It worked fine until I added the init into the classes.
I'm using visual studio code, where before I added the init hovering over name in above would display 'name=[literal]"login', yet now only displays 'name = "any"'
However, when hovering over name in the login class in my new code, it also returned 'name = [literal]login'.
Rather, I want to be able to use the name without having to indent the other attributes into my sm.add_widget.
While I did try putting the attributes in to see what would work, I tended to put:
sm.add_widget(LoginWindow(name="login", email=LoginWindow.email, password=LoginWindow.password, checkBox=LoginWindow.checkBox))
As I simply wanted the instances of the attributes, but I don't think that's what I should do as it only got me error.
line 352, in <module>
sm.add_widget(LoginWindow(name="login", email=LoginWindow.email, password=LoginWindow.password, checkBox=LoginWindow.checkBox))
AttributeError: type object 'LoginWindow' has no attribute 'email'
Thanks to anyone who'd be able to help out.
When you define a method as you have:
def __init__(self, email, password, checkBox, **kwargs):
all those arguments are required whenever an instance of LoginWindow is created. Your code:
sm.add_widget(LoginWindow(name="login"))
does not provide those required arguments, thus you get that error. You can instead use optional arguments by using keywords. See the documentation.

Accessing a widget with a specific id from a different class

I am struggling to find a way to access a widget by its id in another class.
Here comes a code example that will make it easy for you to understand.
class LoginScreen(Screen):
def login(self, username, password):
if user_exists(username, password):
self.manager.current = "login_success"
class LoginSuccess(Screen):
pass
.kv
<LoginSuccess>
Label:
id: greeting
text: "" #this should be "Hey, "+username
I have access to username in the login method of the LoginScreen class, but I need to use that variable in the LoginSuccess class.
How can I do that
Still missing a bit of information (the name property of your LoginSuccess Screen). In your login() method try:
self.manager.get_screen("the_name_of_your_LoginSuccess_Screen").ids.greeting.text = "Hey, "+username

trouble with scope related variables

Hello fellow programmers, I'm developing a simple interface application in Python that will enable easy and intuitive entry of inventory forms in an access database.
I currently have a function as follows:
def spawnerror(self, errormsg):
self.running = False
content = Button(text=errormsg)
popup = Popup(title='ERROR!', content=content, auto_dismiss=False)
content.bind(on_press=popup.dismiss)
popup.open()
And I have appropriate error handling done, and the application uses this function as intended. For example, if someone doesn't enter in a required field, it calls this function and spawns an error page with an error and informs the user.
My issue that I run into is that, it needs to set the class variable running to False, because at the end of the main function "submit" it checks for that and if self.running == False, then it needs to skip the execution of data entry in the access database.
Why is this function not setting the class variable of running to false?
Solution - using App.get_running_app()
In the example, a class attribute, running is defined as BooleanProperty. In the spawnerror() function, it uses App.get_running_app() function to get an instance of App class and then access variable, running.
Note
If running, spawnerror() function and submit() function are in different classes then work out the relation of the classes and pass a direct reference between them.
Example
main.py
from kivy.app import App
from kivy.uix.popup import Popup
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import BooleanProperty, ObjectProperty
class RootWidget(BoxLayout):
instance = ObjectProperty(None)
def __init__(self, **kwargs):
super(RootWidget, self).__init__(**kwargs)
self.instance = App.get_running_app()
self.spawnerror('Testing')
def spawnerror(self, errormsg):
self.instance.running = False
content = Button(text=errormsg)
popup = Popup(title='ERROR!', content=content, auto_dismiss=False)
content.bind(on_press=popup.dismiss)
popup.open()
class TestApp(App):
running = BooleanProperty(True)
def build(self):
print("\nbuild:")
self.display_attributes()
return RootWidget()
def on_stop(self):
print("\non_stop:")
self.display_attributes()
def display_attributes(self):
print("\tApp.running =", self.running)
if __name__ == "__main__":
TestApp().run()
Output

Inheriting setUp method Python Unittest

I have a question regarding unittest with Python! Let's say that I have a docker container set up that handles a specific api endpoint (let's say users, ex: my_site/users/etc/etc/etc). There are quite a few different layers that are broken up and handled for this container. Classes that handle the actual call and response, logic layer, data layer. I am wanting to write tests around the specific calls (just checking for status codes).
There are a lot of different classes that act as Handlers for the given endpoints. There are a few things that I would have to set up differently per one, however, each one inherits from Application and uses some methods from it. I am wanting to do a setUp class for my unittest so I don't have to re-establish this each time. Any advice will help. So far I've mainly seen that inheritance is a bad idea with testing, however, I am only wanting to use this for setUp. Here's an example:
class SetUpClass(unittest.TestCase):
def setUp(self):
self._some_data = data_set.FirstOne()
self._another_data_set = data_set.SecondOne()
def get_app(self):
config = Config()
return Application(config,
first_one=self._some_data,
second_one=self._another_data_set)
class TestFirstHandler(SetUpClass, unittest.TestCase):
def setUp(self):
new_var = something
def tearDown(self):
pass
def test_this_handler(self):
# This specific handler needs the application to function
# but I don't want to define it in this test class
res = self.fetch('some_url/users')
self.assertEqual(res.code, 200)
class TestSecondHandler(SetUpClass, unittest.TestCase):
def setUp(self):
different_var_thats_specific_to_this_handler = something_else
def tearDown(self):
pass
def test_this_handler(self):
# This specific handler needs the application to function
# but I don't want to define it in this test class
res = self.fetch('some_url/users/account/?something_custom={}'.format('WOW'))
self.assertEqual(res.code, 200)
Thanks again!!
As mentioned in the comments, you just need to learn how to use super(). You also don't need to repeat TestCase in the list of base classes.
Here's the simple version for Python 3:
class TestFirstHandler(SetUpClass):
def setUp(self):
super().setUp()
new_var = something
def tearDown(self): # Easier to not declare this if it's empty.
super().tearDown()
def test_this_handler(self):
# This specific handler needs the application to function
# but I don't want to define it in this test class
res = self.fetch('some_url/users')
self.assertEqual(res.code, 200)

Input superclass variables in Python

I'm building a web crawler with Python. I created a parent class to save the user and the password, that I'd like to be inputed via keyboard.
The parent class looks like this:
class ParentCrawler(object):
def __init__(self):
"""Saves the user and the password"""
self.user = input("Email: ")
self.password = getpass.getpass("Password: ")
Then I created a subclass of that parent class with the idea of running parallel instances of it to make the crawling faster. But everytime I create a new object of the child class, I'm asked to input user and pass again, like in the pic below, and that's not what I want.
When a child object is created...
I know I could just hard code my user and pass into the parent class constructor method, but I'd like to know how to input them manually every time the program runned.
Th __init__ method of a class will be run every time you create a new instance. Since this values are needed just once, and you don't need different values for them for each instance, it makes little sense for their values to be requested inside the class initialiser, or other method.
Moreover, if your classes have nothing to do with user interaction on the terminal, there is no reason to hardcode this user interaction in the class code - if you make modifications to your program that will use the same class, and get this information from a configuration file, or from a POSTed web form, for example, you won't be able to use these classes in this way.
There is nothing wrong to pass the credentials as mandatory values when instantiating a class. To continue development and use of your program using it interactivelly at the terminal, you can create a simple function that will request these input data, and return them -
NUM_WORKERS = 4
def get_credentials():
user = input("Email: ")
password = getpass.getpass("Password: ")
return user, password
def main():
workers = []
user, password = get_credentials()
for i in range(NUM_WORKERS):
worker = Crawler(user, password)
workers.append(worker)
worker.start()
...
class Crawler:
def __init__(self, user, password):
...

Categories

Resources