Test Engineering Notes
3.81K subscribers
177 photos
2 videos
647 links
Україномовний канал про технічні аспекти тестування, розподілені системи, блокчейн.

Консультації з автоматизації, менторинг, тестові співбесіди - @al8xr
Download Telegram
Про динамічність типізації

#python #engineering

Коли я ще писав на Java, я був в курсі, що існують статично-типізовані та динамічно-типізовані мови програмування.

В динамічно-типізованих мовах, як-от Python чи Javascript, тип перевіряється під час запуску.
Тому ніхто не забороняє писати щось типу такого:

x = 10       # x - integer
x = "Hello" # x - string


Можна навіть написати функцію, яка буде працювати з різними типами

def add(a, b):
return a + b

print(add(5, 10)) # Працює з integers
print(add("Hello, ", "Alex!")) # Працює з strings


В статично-типізованих мовах (C++, Java, C#) компілятор перевіряє правильність типів ще на етапі компіляції (до запуску коду).
Тому компілятор буде скаржитись як на етапі визначення змінної

int x = 10;        // x - integer
x = "Alex"; // Compile-time error: incompatible types


так і при роботі з функціями:

public int add(int a, int b) {
return a + b;
}

public static void main(String[] args) {
System.out.println(add(5, 10)); // Works with integers
System.out.println(add("Hello, ", "Alex!")); // Compile-time error
}


Погляд під іншим кутом

Протягом якогось часу я просто думав, що Python динамічно-типізований так само, як JS та не переймався.
Але в системі координат типізованості є ще одна вісь. Мова можна бути зі слабкою (weak) та сильною (strong) типізацією.

Python - мова з сильною типізацією. Інтерпретатор все-таки слідкує за типами та може генерувати TypeError у випадках жорсткого порушення правил.

a = "Hello"
b = 5
c = a + b # Спричинить TypeError: бо додавати можемо тільки str (не "int")

d = a + str(b) # Python вимагає явного перетворення даних
print(d) # Hello5


Те ж саме з функціями:

def add_numbers(a: int, b: int) -> int:
return a + b

result = add_numbers(3, "4") # Знову буде TypeError: unsupported operand type(s) for +: 'int' and 'str'


JS - це мова зі слабкою типізацією.
Компілятор дозволяє як завгодно працювати з типами та багато чого робить "під капотом" - неявно.
Саме через ці неявні перетворення в JS так багато "магії".

// звичайні динамічні типи
var a = 10;
a = "Now I'm a string"; // Тип a був змінений з number на string
console.log(a); // Output: Now I'm a string

// JS робить магію
var a = "Hello";
var b = 5;
var c = a + b; // Помилки не буде. JavaScript спробує сконвертувати b в строку та виконати конкатенацію
console.log(c); // Hello5

// Інший приклад
var e = 1;
var f = "2";
var g = e - f; // JavaScript робить число з f та віднімає
console.log(g); // Output: -1


Висновок

Хоч Python всі називають мовою, де можна як завгодно працювати з типами, це не так. Все-таки є в Python є деякі обмеження (може навіть на краще).
Найбільша свобода все-таки в JS. Але найбільша свобода може бути причиною найбільшої "головної болі" та багів.
18👍5
Корисні "трюки" в Python

#python #tricks

Сьогодні дозвольте поділитись прикладами трюків з книги "Python One-Liners".
Користуйтесь ними для навчання, або будьте готові отримати шось подібне на співбесіді (зустрічав таке).

1. У вас є строка з багатьма рядками. Перетворіть її на масив масивів слів в кожному рядку, якщо слово має більше трьох літер.
text = '''Call me Ishmael. Some years ago - never mind how long precisely - having  
little or no money in my purse, and nothing particular to interest me
on shore, I thought I would sail about a little and see the watery part
of the world. It is a way I have of driving off the spleen, and regulating
the circulation. - Moby Dick'''


Очікуваний результат:
[['Call', 'Ishmael.', 'Some', 'years', 'never', 'mind', 'long', 'precisely', 'having'], ['little', 'money', 'purse,', 'nothing', 'particular', 'interest'], ['shore,', 'thought', 'would', 'sail', 'about', 'little', 'watery', 'part'], ['world.', 'have', 'driving', 'spleen,', 'regulating'], ['circulation.', 'Moby', 'Dick']]


Рішення:
w = [[x for x in line.split() if len(x)>3] for line in text.split('\n')]


2. Прочитайте файл, видаліть для кожного строки непотрібні пробіли та збережіть це все в лист.

Рішення:
print([line.strip() for line in open("readFile.py")])


3. Маючи словник з даними щодо компаній та заробітних плат співробітників, поверніть список компаній, що платять менше ніж 9$ на годину.

companies = {  
    'CoolCompany' : {'Alice' : 33, 'Bob' : 28, 'Frank' : 29},
    'CheapCompany' : {'Ann' : 4, 'Lee' : 9, 'Chrisi' : 7},
    'SosoCompany' : {'Esther' : 38, 'Cole' : 8, 'Paris' : 18}
}


Рішення:
illegal = [x for x in companies if any(y<9 for y in companies[x].values())]


P.S. Трюки корисні, коли ви та ваші колеги розумієте як вони працюють.
18
Behavior Driven Chaos with AWS Fault Injection Simulator

#testing #python #chaos

Якщо ваша інфраструктура на AWS та маєте бажання перевірити стійкість системи - можна застосувати підхід хаос інжинірингу.
Більше про підхід можна почитати тут.

Amazon випустив окремий інструмент для таких цілей - AWS Fault Injection Simulator.

Подивитись приклад на Python (та навіть з BDD!!!):

git clone https://github.com/aws-samples/aws-fis-behaviour-driven-chaos.git
👍8
🐍Is Python Really That Slow? 🚤

#python #performance

Доволі цікаве порівняння швидкості між Python (CPython та PyPy рантайм різних версій), Node.js та Rust. Порівнювали на базових алгоритмах, типу Фібоначчі чи сортування.

Здається, переможець очевидний.

Треба відмітити, що PyPy рантайм останньої версії значно покращив свої показники та став навіть краще, ніж node. Але до Rust ще рости й рости.

Для тих, хто хоче дізнатись різницю між CPython та PyPy - маю окрему статтю.
👍111🤮1
Чи правда шаурма стає гіршою чим ближче до станції метро ...

#engineering #python

Цієї пʼятниці хочу поділитись дуже цікавою історією про те, як одна фраза на Reddit може привести до повноцінного проєкту з аналізу даних.

А точніше - приклад того, як можна інженерно підходити до перевірки гіпотез.
👍22🤡1
Що краще: enumerate чи range для циклів

#python

Уявімо, що треба пройти по усім елементам циклу.

Це можна зробити дуже просто


fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
print(fruit)


Якщо ж треба мати доступ до елементу разом із його індексом, є такі варіанти


# range
fruits = ["apple", "banana", "cherry"]
for index in range(len(fruits)):
print(index, fruits[index])

# enumerate
fruits = ["apple", "banana", "cherry"]
for index, fruit in enumerate(fruits):
print(index, fruit)


Що краще обрати - enumerate чи range?

1. enumerate більш чисто виглядає та ще й оптимізована на рівні інтерпертатора
2. enumerate не має потенційних проблем з доступом по неіснуючому індексу
3. enumerate дозволяє задати початковий індекс для ітерації


for index, fruit in enumerate(fruits, start=1):
print(index, fruit)


Окей, а коли ж краще користуватись range?

- коли колекція елементів точно індексована
- коли не треба мати доступ до конкретного елементу за поточним індексом


for i in range(10):
print(i**2)
👍151
Vibe coding ... ти не пройдеш!

#python #bugs

🗺 Ситуація

Ви тест інженер та працюєте в команді з розробниками.
До команди приєднується новий девелопер. Він ... дуже полюбляє vibe coding, але не любить vibe debugging.

Через деякий час, ви бачите від нього PR на задачу обробки дорослих юзерів та фільтрації тих, у кого є валідна електрона адреса.


def process_user_data(users, min_age=18):
results = []
for user in users:
name = user['name']
age = user['age']
email = user['email']
if age >= min_age:
if '@' in email:
user['status'] = 'processed'
results.append(user)

average_age = sum(user['age'] for user in results) / len(results)
print(f"Average age of processed users: {average_age}")

return results


Питання: чи все ок з цим кодом? Відповіді пишемо в коментарях.
😁10🥴81
Найшвидший спосіб знайти голосні в реченні

#python

Задача: написати функцію, яку перевіряє чи є голосні в рядку.


def has_vowels(s: str) -> bool:
...


Можна це зробити багатьма способами.

Спосіб 1


def loop_in(s):
for c in s:
if c in "aeiouAEIOU":
return True
return False


Спосіб 2


def set_intersection(s):
return set(s) & set("aeiouAEIOU")


Спосіб 3


def map_lambda(s):
return any(map(lambda x: x in "aeiouAEIOU", s))


Але виявляється, що найшвидший спосіб це - регулярні вирази!


import re
def regex(s):
return bool(re.search(r'[aeiouAEIOU]', s))


Чому? Бо механізм регулярних виразів в Python дуже оптимізований. Більше можна почитати в оригінальній статті.
👍23❤‍🔥51
Як ШІ замінить менеджерів

#python #ai


import time
import random

def random_status_prompt():
prompts = [
"What is your current status?",
"Any blockers?",
"Update your JIRA, please."
]

# Sleep for a random number of minutes (converted to seconds)
sleep_minutes = random.randint(1, 10)
print(f"Sleeping for {sleep_minutes} minute(s)...")
time.sleep(sleep_minutes * 60)

# Pick a random prompt and display it
message = random.choice(prompts)
print(message)

if __name__ == "__main__":
random_status_prompt()
😁67👏1