R.....y
R.....y
#naukaprogramowania #programowanie #python

Mam bardzo prostą metodę w klasie:

def save_to_file(self, path):
try:
with open(path, 'w') as file:
file.write(json.dumps(self.data, indent=4))
except PermissionError:
print(f"no permissions to save the file in {path}")

Chcę odpalić unit test:

def test_write_to_file_without_permissions(self):
d = data_getter(LoadFromFile=True, data_path='data.json')
self.assertRaises(PermissionError, d.save_to_file, 'no_permissions_to_write/data.json')

Problem jest taki, że jeżeli zostawię blok except w metodzie, to wtedy unit test go nie łapie. Jeżeli wyrzucę nowy error w bloku except, to zaliczam test, ale sam program wtedy się będzie wywalać.
W jaki sposób mogę zachować block except, żeby test case wykrywał że dostałem w ryj wyjątkiem nieobsłużonym?
0
  • Najlepsze
  • Wszystkie komentarze
CancerLight
@RedveKoronny: najszybciej ale najgorzej - mock na printa i sprawdzasz mockprint.assertcalledoncewith("no permissions to save the file in data.json").

Żeby zrobić to jak człowiek printa zastąp loggiem i użyj caploga (nie wiem czy unittest wspiera), używaj pytesta
2
R.....y
R.....y
@RedveKoronny: czytaj: żebym mógł odpalić testy bez zmiany kodu
0
Saly
@RedveKoronny: xd, chcesz żeby leciał wyjątek ale tak, żeby nie leciał.
0
Saly
@RedveKoronny: normalnie przepuść wyjątek w metodzie save_to_file i złap go tam, gdzie wywołujesz tą metodę
0
R.....y
R.....y
@Saly: chce żeby był ślad że był (tak jak zaplanowałem), ale żeby sam program sie nie w---------ł, skoro go obsłużyłem
0
R.....y
R.....y
@Saly: no dobra, ale wtedy dalej muszę zmieniać kod, tylko po to żeby odpalić raz test, a potem go zmienić z powrotem, żeby program działał
0
Gantzu
Gantzu
@RedveKoronny: @unittest.mock.patch('builtins.print')
def testwritetofilewithoutpermissions(self, printmock)
...
printmock.assertcalled_once()
0
CancerLight
@RedveKoronny: druga sprawa, nie używaj assertRaises - https://www.youtube.com/watch?v=Q_HMOBD09ts
0
Saly
@RedveKoronny: jak testujesz jakiś kod to zakładasz, że jest on reużywalny. Czyli jest sens go użyć w różnych sytuacjach i miejscach. W takim wypadku najlepiej przepuścić wyjątek, bo dajesz maksymalną swobodę użytkownikowi przez co twój kod jest prostrzy i można z nim więcej zrobić.

Jak dana klasa ma nie być reużywalna to dobry znak, że nie warto jej testować. Spróbój przetestować poziom wyżej, czyli funkcję/klasę, która jej używa. Często pisze
0
dziekujemyzapraszamyponownie
dziekujemyzapraszamyponownie
@RedveKoronny: zacznij szukac od 'mock exceptions python'. generalnie slowo kluczowe 'mock' to wazna czesc pisania testow, bo ciebie jako programiste niezbyt obchodzi np. czy dana implementacja bazy danych prawidlowo sie komunikuje. dostajesz specyfikacje/biblioteke do obslugi i jedziesz - zakladajac ze ta biblioteka/baza maja swoje testy i dzialaja tak jak powinny.
0
R.....y
R.....y
@dziekujemyzapraszamyponownie: @Saly: @CancerLight: @Gantzu:
A czy zrobienie czegoś takiego ma sens, jeżeli chcę poinformować użyszkodnika gdzie nastąpił, jaki błąd, czy wypieprzyc w ogóle ten block try-catch razem z logami?
0
R.....y
R.....y
@RedveKoronny: dobra, zrobiłem:
if os.access(path, os.W_OK)
0
dziekujemyzapraszamyponownie
dziekujemyzapraszamyponownie
@RedveKoronny: nie rozmawiam w pythonie, ale wyglada w miare sensownie. poza tym, ze jak juz obslugujesz wyjatek, to nie rzucasz uzytkownikowi wyjatkiem ;) zapisz do loga, zapisz w tracking, ale uzytkownikowi zwroc 'ladnie' blad.

cos co spowoduje np. w aplikacji desktopowej wyskoczenie okienka/wyraznego powiadomienia, ze nie udalo sie zapisac pliku, bo costam - nie ma uprawnien, sciezka zapisu nie istnieje, plik nie istnieje, gwiazdy sa zle ustawione etc. tak, zeby
0
R.....y
R.....y
@dziekujemyzapraszamyponownie: wyciepałem w ogóle bloki trycatch z tej klasy, tak jak poradzono mi wyżej, wywołam to jedynie w głównej funkcji. Logi i tak są elegancko robione, to user będzie chyba wiedział co sie zwaliło
0
Gantzu
Gantzu
@RedveKoronny: zależy jeżeli chcesz mieć error w logach to zostaw (nie wiem jak na innym poziomie ten wyjątek traktujesz). Jak robisz raise w bloku except to nie dopisuj klasy wyjątku, wtedy oryginalny wyjątek razem ze stack tracem zostanie rzucony
0
CancerLight
@RedveKoronny: os.access(path, W_OK) nie ma sensu, gdy ścieżka jeszcze nie istnieje, a może się pojawić przypadek, że scieżka nie będzie relatywna do cwd
0
R.....y
R.....y
@Gantzu: nie traktuje, zostawiałem żeby mi testy przechodziły ( ( ͡°( ͡° ͜ʖ( ͡° ͜ʖ ͡°)ʖ ͡°) ͡°) ). Teraz to troche rozsądniej dam, potem moge podesłać cały kod, tylko napisze od nowa testy z pytestem, i usune swoje klucze do api
0
R.....y
R.....y
@CancerLight: w tym bloku sprawdzam jedynie permisje. Spróbuje dodać jakiś dodatkowy system, który upewni sie że są wszystkie pliki, i że dane są w prawidłowej formie. Teraz robie prowizorke, ale sie potem refactor walnie
0
CancerLight
@RedveKoronny: to Ci mówię, że os.access w tym wypadku nie pokrywa wszystkich przypadków
0
R.....y
R.....y
@CancerLight: a co pokrywa, żeby nie rzucać userowi w twarz wyjątkiem po obsłużeniu go?
0