Mock a logger defined in the constructor using pytest - python-3.x

I have this class defined:
class User():
def __init__(self):
self.logger = Logger('user.log')
def get_data(self):
_data = {
'username': 'abc'
}
_payload = json.dumps(_data)
self.logger.info("Loaded payload")
return _payload
The test case written for get_data():
#mock.patch('mymodule.file_user.Logger')
def test_get_data(self,mock_logger):
assert User().get_data() == "'username': 'abc'"
mock_logger.info.assert_called_once_with(
'Loaded payload')
The mocking here fails giving the assertion error "Expected 'info' to be called once. Called 0 times."

Logger is a class, self.logger.info() is an instance method. So you need to get the instance of mock_logger via .return_value.
E.g.
logger.py:
class Logger():
def __init__(self, filepath) -> None:
pass
def info(message):
print(message)
user.py:
import json
from logger import Logger
class User():
def __init__(self):
self.logger = Logger('user.log')
def get_data(self):
_data = {
'username': 'abc'
}
_payload = json.dumps(_data)
self.logger.info("Loaded payload")
return _payload
test_user.py:
import unittest
from unittest import mock
from user import User
class TestUesr(unittest.TestCase):
#mock.patch('user.Logger')
def test_get_data(self, mock_logger):
mock_logger_instance = mock_logger.return_value
user = User()
actual = user.get_data()
self.assertEqual(actual, '{"username": "abc"}')
mock_logger_instance.info.assert_called_once_with('Loaded payload')
if __name__ == '__main__':
unittest.main()
unit test result:
⚡ coverage run /Users/dulin/workspace/github.com/mrdulin/python-codelab/src/stackoverflow/66366372/test_user.py && coverage report -m --include='./src/**'
.
----------------------------------------------------------------------
Ran 1 test in 0.002s
OK
Name Stmts Miss Cover Missing
-----------------------------------------------------------------------
src/stackoverflow/66366372/logger.py 5 2 60% 3, 6
src/stackoverflow/66366372/test_user.py 13 0 100%
src/stackoverflow/66366372/user.py 10 0 100%
-----------------------------------------------------------------------
TOTAL 28 2 93%

Related

ImproperlyConfigured: circular import and also urls of project does have patterns in it

my url of project
from django.contrib import admin
from django.urls import path,include
urlpatterns = [
path('admin/', admin.site.urls),
path('',include('learn.urls')),
]
url of my app
from django.urls import path
from .import views
urlpatterns = [
path('',views.home,name='home'),
path('notes',views.notes,name='notes'),
path('delete_note/<int:pk>',views.delete_note,name='delete_notes'),
path('detail/<int:pk>',views.detail.as_view(),name='detail'),
path('homework',views.work,name='homework'),
path('delete_hw/<int:pk>',views.delete_hw,name='delete_hw'),
path('update/<int:pk>',views.update,name='update'),
path('todo',views.todo,name=todo),
]
my views
from django.shortcuts import render,redirect
from .forms import *
from .models import *
from django.contrib import messages
from django.views.generic.detail import DetailView
def home(request):
return render(request,'website/home.html')
def notes(request):
if request.method == 'POST':
form= notesform(request.POST)
if form.is_valid():
notes = Notes(user=request.user,title=request.POST['title'],description=request.POST['description'])
notes.save()
messages.success(request,f"Notes of {request.user.username} is added successfully")
form = notesform()
notes= Notes.objects.filter(user=request.user)
context= {'notes':notes,'form':form}
return render(request,'website/notes.html',context)
def delete_note(request,pk=None):
Notes.objects.get(id=pk).delete()
return redirect('notes')
def work(request):
if request.method == 'POST':
form = homeworkform(request.POST)
if form.is_valid():
try:
finished = request.POST['is_finish']
if finished == 'on':
finished = True
else:
finished = False
except:
finished = False
homeworks= homework(
user= request.user,
subject = request.POST['subject'],
title = request.POST['title'],
description=request.POST['description'],
due= request.POST['due'],
is_finish = finished
)
homeworks.save()
else:
form = homeworkform()
Homework= homework.objects.filter(user=request.user)
context = {'Homework':Homework,'form':form}
return render(request,'website/hw.html',context)
def delete_hw(request,pk=None):
homework.objects.get(id=pk).delete()
return redirect('homework')
def update(request,pk=None):
Homework = homework.objects.get(id=pk)
if Homework.is_finish == True:
Homework.is_finish = False
else:
Homework.is_finish = True
Homework.save()
class detail(DetailView):
model = Notes
template_name = 'website/notes_detail'
redirect('notes')
def todo (request):
return render(request,'website/todo.html')
my models
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Notes(models.Model):
user= models.ForeignKey(User,on_delete=models.CASCADE)
title=models.CharField(max_length=200)
description=models.TextField()
def __str__(self):
return self.title
class homework(models.Model):
user = models.ForeignKey(User,on_delete=models.CASCADE)
subject = models.CharField(max_length=100)
title = models.CharField(max_length=100)
description = models.TextField()
due = models.DateTimeField()
is_finish = models.BooleanField(default=False)
def __str__(self):
return self.title
class Todo(models.Model):
user = models.ForeignKey(User,on_delete=models.CASCADE)
title = models.CharField(max_length=100)
is_finish = models.BooleanField(default=False)
this is my codes i don't know the where and why this occurs
this is it shows
raise ImproperlyConfigured(msg.format(name=self.urlconf_name)) from e
django.core.exceptions.ImproperlyConfigured: The included URLconf 'studyportal.urls' does not appear to have any patterns in it. If you see valid patterns
in the file then the issue is probably caused by a circular import.

inheritance and init pattern with asyncio in python

Searching the web i could not find a lot of answers regarding classes and init-patterns in python for inheritance. I would like to use something like the following pattern. Are there any disadvantages for this pattern? One maybe is that there could be no init method for the child.
import asyncio
class Foo(object):
def __init__(self):
self.something = None
#classmethod
async def create(cls, something):
self = cls()
self.something = something
return self
class FooChild(Foo):
def __init__(self):
#...
super().__init__()
#classmethod
async def create(cls, something):
self = await super().create(something)
#...
return self
async def main():
something = "something"
foo = await FooChild.create(something)
if __name__ == '__main__':
asyncio.run(main())

Access app_context from custom Converter in Quart

Is there a solution to get the app context in a class that inherit werkzeug BaseConverter class?
This is my example running in Flask:
from werkzeug.routing import BaseConverter
class CodeConverter(BaseConverter):
app = None
def to_python(self, value):
# Create an app context to get value from db
# and instantiate a class X as obj
return obj
def to_url(self, obj):
value = obj.code
title = obj.title
return "%s/%s"%(value, title)
def crate_app():
...
app.url_map.converters['code'] = CodeConverter
CodeConverter.app = app
...
Well, this works for me.
from werkzeug.routing import BaseConverter
class CodeConverter(BaseConverter):
app = None
async def get_object(self, app, value):
async with app.app_context():
# and instantiate a class X as obj
return obj
def to_python(self, value):
pool = concurrent.futures.ThreadPoolExecutor()
result = pool.submit(asyncio.run, self.get_object(self.__class__.app, value)).result()
return result
def to_url(self, obj):
value = obj.code
title = obj.title
return "%s/%s"%(value, title)
def crate_app():
...
app.url_map.converters['code'] = CodeConverter
CodeConverter.app = app
...

Trying to mock two classes with Groovy Spock Mock: GroovyCastException

I try to mock two classes in a Jenkins Pipeline var-script, but however I order the definition of the Mock I receive a GroovyCastException, while the mock for the second class is initiated
org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'Mock for type 'ClassA'' with class 'com.pipeline.ClassA$$EnhancerByCGLIB$$9b005c28' to class 'com.pipeline.DBReader'
This is how my Spock-Test looks like:
import com.homeaway.devtools.jenkins.testing.JenkinsPipelineSpecification
import com.pipeline.ClassA
import com.pipeline.DBReader
import groovy.sql.Sql
import org.jenkinsci.plugins.workflow.steps.FlowInterruptedException
import hudson.model.Result
class execScriptSpec extends JenkinsPipelineSpecification {
def execPipelineScript = null
def mockStage = [timeout: [time: 'mocktime']]
def mockScript = [...]
def setup() {
execPipelineScript = loadPipelineScriptForTest("vars/execScript.groovy")
}
def "Test Pipeline-Script"() {
setup:
GroovyMock(ClassA, global: true)
new ClassA(*_) >> Mock(ClassA) {
loadScope(_) >> null
loadJsonFromURL(_) >> null
}
GroovyMock(DBReader, global: true)
new DBReader(*_) >> Mock(DBReader) {
loadDBDriver(_) >> null
}
when:
execPipelineScript(mockScript, mockStage)
then:
true
And that is the code under test:
import com.pipeline.DBReader
import com.pipeline.ClassA
def call(script, stage) {
def pipelineConfig = script.pipelineConfig
def stageStatus = pipelineConfig.general.stageStatus
def projectName = script.env.project
// DB connection parameters
def dbName = script.deliveryConfig.system.dbName
def dbSchema = script.deliveryConfig.system.dbSchema
def dbServer = script.deliveryConfig.system.dbServer
def dbUser = script.deliveryConfig.system.dbUser
// DB Driver to use
def dbDriver = script.deliveryConfig.system.dbDriver
def dbPassword = script.env.password
// Create new DB-Client
DBReader dbClient = new DBReader(dbName, dbSchema, dbServer, dbUser, dbPassword, dbDriver)
dbClient.loadDBDriver()
def contextParameter = script.params['Context']
ClassA mapGavToVersionRange = new ClassA(projectName, contextParameter, script)
classAInstance.loadDeliveryScope( dbClient )
def url = 'https://some.valid.url'
classAInstance.loadJsonFromURL(url)
...
So don't get me wrong: The actual mocking of one or the other class works (if I put only one of them in my test), but as soon as I put both of them, the second one will not work. And I currently have no idea, why this happens.
Would be great, if anybody has an idea :-)
Thanks a lot!

key: expected bytes or bytearray, but got 'int'

from flask import Flask, render_template,request,url_for,make_response,redirect,session
from bs4 import BeautifulSoup
import sqlite3
import random
import models
import os
import socket
app = Flask(__name__)
app.config['SECRET_KEY'] = b"HelloWorld"
def check_session():
try:
loggedin = session['loggedin']
except:
session['loggedin'] = False
loggedin = session['loggedin']
return loggedin
#app.route('/')
def index():
loggedin = check_session()
#loggedin = True
blogpost = models.Blogpost()
posts = blogpost.conn.execute("SELECT path FROM posts ORDER BY timestamp DESC")
post_content = []
for post in posts:
post_text = BeautifulSoup(open(post[0],'r').read(),'html.parser')
post_content.append(post_text)
return render_template('home.html',loggedin=loggedin,post_content=post_content)
#return "HelloWorld"
#app.route('/login',methods = ['GET','POST'])
def login():
if request.method == 'GET':
return render_template('login.html',strike=0)
elif request.method == 'POST':
username = request.form['username']
password = request.form['password']
user = models.User(username)
result = user.authenticate(username,password)
if result == False:
session['loggedin'] = True
session['username'] = username
return render_template(home.html, session['loggedin']
if socket.gethostname() == "DESKTOP-D18" :
if __name__ == '__main__':
app.secret_key=1
app.run(host=os.getenv('IP', '127.0.0.1'),port=int(os.getenv('PORT', 8080)),debug=True)
else :
if __name__ == '__main__':
app.secret_key=1
app.run(host=os.getenv('IP', '0.0.0.0'),port=int(os.getenv('PORT', 8080)),debug=True)
This is my Flask app. When I run it , it gives the following error:
key: expected bytes or bytearray, but got 'int'
This would be much easier to answer with a line number.
My guess might be that you are trying to convert an int to an int here:
port=int(os.getenv('PORT', 8080))
8080 is already an int. Does it work if you do:
port=int(os.getenv('PORT', '8080'))

Resources