From 1db14658e1ca9c2954e169b4e02b5fb7defdae65 Mon Sep 17 00:00:00 2001 From: akhdanre Date: Thu, 8 May 2025 02:45:48 +0700 Subject: [PATCH] feat: adding unit test for repository --- ...er_repository.cpython-310-pytest-8.3.4.pyc | Bin 0 -> 6081 bytes ...iz_repository.cpython-310-pytest-8.3.4.pyc | Bin 0 -> 9117 bytes ...on_repository.cpython-310-pytest-8.3.4.pyc | Bin 0 -> 6305 bytes ...ct_repository.cpython-310-pytest-8.3.4.pyc | Bin 0 -> 7179 bytes ...er_repository.cpython-310-pytest-8.3.4.pyc | Bin 0 -> 8167 bytes test/repository/test_answer_repository.py | 109 +++++++++++ test/repository/test_quiz_repository.py | 171 ++++++++++++++++++ test/repository/test_session_repository.py | 116 ++++++++++++ test/repository/test_subject_repository.py | 139 ++++++++++++++ test/repository/test_user_repository.py | 155 ++++++++++++++++ 10 files changed, 690 insertions(+) create mode 100644 test/repository/__pycache__/test_answer_repository.cpython-310-pytest-8.3.4.pyc create mode 100644 test/repository/__pycache__/test_quiz_repository.cpython-310-pytest-8.3.4.pyc create mode 100644 test/repository/__pycache__/test_session_repository.cpython-310-pytest-8.3.4.pyc create mode 100644 test/repository/__pycache__/test_subject_repository.cpython-310-pytest-8.3.4.pyc create mode 100644 test/repository/__pycache__/test_user_repository.cpython-310-pytest-8.3.4.pyc create mode 100644 test/repository/test_answer_repository.py create mode 100644 test/repository/test_quiz_repository.py create mode 100644 test/repository/test_session_repository.py create mode 100644 test/repository/test_subject_repository.py create mode 100644 test/repository/test_user_repository.py diff --git a/test/repository/__pycache__/test_answer_repository.cpython-310-pytest-8.3.4.pyc b/test/repository/__pycache__/test_answer_repository.cpython-310-pytest-8.3.4.pyc new file mode 100644 index 0000000000000000000000000000000000000000..31a9a72448f9c682233277266e0b55f4c8317afa GIT binary patch literal 6081 zcmbtY%a0sK8SmFj&-6TY*1NI2u>&R{;0eyY{D?zrV~042A=!}F4$vZM%}({MXEU!< z*Ti1aD*^T;5_VnPF&!?pMW^GxF94XUy` zpJe?ko>)z{mGg7lW;gRK&-b|QGz+bQU*LMCS!|X364$fMa%;w);kw(bv}XNT(+IO$ z2SiTf?;3YZe~#}wQQ*6IQ4D7`EKw5WyN>^em=Tq`hJR4ZiUYVF5_4i6*TdowaS+!9 zaY!7-^--}P9>w*DI3kYXdQ_NKjp}3f@KwgzzM14-t!*~yuXgHhSIs2%+WJ;lS62kp zMNNgO(F$QSe?1E2rFL{Ply8LHPSj8xxec4jsQq$VH59jLyDKVe>9#rzHU4Mf=9~CM zSrp2+V_Y@%%{6J^Zr_k_hA!@ZZ>iN*OQI3gSC;A>5iY44Vbq9%cY2N6L05KYs!M#+ zs=Xb`B^5?$Ne<`7_d$(k9gLb6yW5G|!uJMZogfg=xLHes5*Z6ogNknRzagJ!dppJFOlzIY3m&+v8ujDjt`=4*jD$xgV*jk^sbu>1_&A= zae3*fLL;HYFX)~^5!96L>YKNg9v?xeo5b?<5aUUN3*jdB_$0ZGjyBnsd~F} zQ|75=%O=gA_rVevd!Pz@Gv^Uz|A`^dxM zD))gJEHZ5E?3p6F>l`$8GHM1bl{m9!-Z6gyy4rCBqO0l>Tnmjh{G{NWhPZ#a7SYYI zCy#fxPgNuDhiT>5d2U*+M#rgTr5c^!hSh3R^>z|q1ih$QyB-pTqh3?V1+3S;li1zu zWhz#vSf%1rb(WV}+OS~vCSJYMYyx0FAMnQW2|DdCDe8C#-mNuz=(#RKIM+X*CmGah zcuByp9?Hk4FB&o_UhHlM>%B%(p`#?*?7%EaJhT!K1T~o)4x$^KUQKonL=`kELgbO@L{h?pRn-R5U&7$djDV0Twh&pp@cwh|*QimPTo8 zZkYlEK`14%h=ILxD97=tTxwkakq~Ytu(~mUvn9qEVf7T_Ok)*vGeqJ=vS6%UCW{oS zprfJ1>)Z!n^-b4QtOC zo6&nT9?$4!Jcf>*EZ4IbuP~h1uhx6gjY_-PjU%<+eI z)p=&6#A`uQG%160b?%`sOmZ8@io{9sNxIE%hAO~nVU>t<^eR!#l3%6bI2BbYo}%Jw zRGgsVX(}iQC9_OlOhNTdt6P(yJcRbD$CSd0kvPy=HOY&=L@zGWi(^!>GJbP$L@q5LHkN*ye!sq4hiS_eefyoM4=Zy!Z<|6_7w%#+Dg?UHZ0i zREER}IE8YJ6`QfuGmsbU=(5W8U17#HVwT%EX2CrDJmb*vF_;yPK4cwzS~1{@*k zUYf5lCzW}s={5%^=*-ZbGybIS^# zVfqeaW+n!|?OE_4xA(JbY45@p&^E{(DhF*tp55Ynk?(u#$CIkiFDh`SJd0Y1YNSiR z&I5}V$Rb8R@(Ni{4HlFy1{T-356U?{_n~u+%huq=G+#KXjFy=g86?#a zVs3K(Gw46&{!s()irha0GGA$&(ymQZqo&3Iy<~PY#L8>eG#c{fXzO#U zD=+xeGYw(==&*77iD{H9p3{Q(!s76a+b71d>!*nRRO{PN-3Y5=7-E#B5iqoSlFw4X zeEAyHh%f!ZSkQc~Xpq@4wfB04O715GbSW16rb)iFXJK-LB zKBUN>rtyFz2G$s4}`u`M&P5yDS1v1x?U#&2M8 zi7YruUL=b&N@(LZuy}*}AaeXJ_mK*6wkGuIjo$;v5rW@c0O2ptwvfLHVl@+IA*$Wj zjsAolDk29lZ9-b3of0(nir5g|aQvU6t*9tb|B{|k4N>G_r3N$nh%7jj|Ayb!7ADtO zey5_kC`v<7t*LxmRA&%x?hek;uw5;$$%AmvLnDokG~_9mKpQTn`_xa7pU?ojn+4{v ziDepx{`?XR@e&oJKjj%Jo}uC_3T$0D>2vy@!g)Exd3x9)>44<(;hj{(KmhWWPD($m z3v{q9%WqKk-=^Xs6_=*O<_IS-Jh3a9HR;M8sCQIUAtkX*_3nCs$EpoKX7bIte{D6?!v|&u7=e;-+o9^+>Y%6~EMLHx!M#NXMJ}#lEv1b=n%rBn$mYt=mP9 z=^1V#j3m*Z?@=@Fha%qo`E#R&MLzBz(>zQQccXC&XP2Qq^Q2=Doe}7`f_D%sNLhj~ z?=s{heeKv9@oF)2bLTK@uNht-zeZm{@widMG05QGu|3mqJhSZND!D?goXg?o6$}3b DO3^k~ycG{uoOWr`U-6}{&@OKVD}l&vyRunXsfb)`S2w3trbPDIwaw|3Y1<0D zjTu!^{#|RwUYV7%vI^vEPF2F`HAhv|)LnOFUe(m}U2El#no+YjKBwl?JdTIeA@v-N z&#S}gc^r?ZBkCxQN7W1J7>+Nf7uBb5Jf>b!pT_Y;wV;mU_$l?WdIiUq)MwPIIDT4v zR=tMfg0in#_17QZ$*tvmJ1xK4T#s7sc3U^SXcBA3x@zs)%i6)&zNKjzX&!!XaXQ9kHg?A=aFn|PXr zS}k)8oYix56^9lVHvFMXKahoTO^G#tC*0%PahCCfj#|}xfVwR=AFNwf(3=JabJlP! z^8}8joO(J;`nogrVmKc!zC-2fXgJ@lt!(A&IU*I5n@L6GWfD9mlgf#+TiCO*vp`ic z3Eq=Q@Si@=f=UZ|ruiEcF^!3jF+BlneI!d`#1 z9ks5dE}bY1l5Wy$i>V&)Rj0Lfv>7E0)z?jq{@^8c&Ka$K9O_1|-Mo!aA1GcZH~Y!; zuEyfi(t2O_mrkFl2YLpV^eme>Hi&aeA7b+yo9EdaMU&3n?89#`OQX#tch+Nl4E=Ri z`@CFO4-;J!snfj$yL&foH8qrSKQ;C~ga;3?+|YO&pE|kCN#hsMICg+v7r)N`1%;ZN z1vY!VU+d#g81p^4RSAFMd;blAL9%TpcH-=a4{kdH_{2tG!)+Ad8{WX)v$qSTXScKm zgi8EDAt~=T+wQ=PTgp*|B-pL&Ssz;QiKMzamH2zMUV>Dk)Ug%3E7!P4jX?n#Z&HI2 zG+b58HI`+JGBmEr7?7Y*6m56UR^EO0u(e%GrqMGqDDK%i_IH4w+pa>e*Gr6_O4NZR zlTg8K56?AYo-DljdhhnxdK`Q^6BaH?*Qt8^I(wGt@d@cTU61R*b{a%6MoF5TR>+`= z`|Ttx#EIT_(?aj|DK<-NPO~{%pOsgw8P?iGlLoDByA2e9^)Z&LrvdLyt0q7jA2!>4 zjNH;8-E__@ve9bdCI!V-s6WH8KFhJHmwUGxtNo}AABt12-Gy452IwU&HJUm-(ul8j z`)$<#H0Z{9ySoaf?=&~VwA_fBYazSS+8@fBz>2PD-PP%QW38(YuiX1Qm~i5cbGq}$HO;>-hz=kkGKqM>J3>84KAxo_(W=ooWR z#zyX-iN4kKZmwpY>zWva-c(HD8y}=Md z~F3cclJW)M2=UdXcAPAZi0k$C4R1X36v?y~O4;n=@?AvN^}*Je$v>NgaUv ztVEzhQLDSzYwED>OF-y1sZy4uV`FJbEa*Sr&0pk|k*HW2jf&4tM#UkCihP|2!G1@b z#1JvJXwRO8OSy zyAWSVyxo$r2LG1j942;mIu z8SI|=PjNnGHSXs*qHX1f1`M-lxugJOa}Bbsv#$ti+OVs)QKDTpd~Bf>F-&>)+-)Z* z51bufoN}=R7X~hnq&O(XJtBcB4T`WZwrC&d$_lj%wgWY=NyzUFGrjn0G-uruK5emoQLMWh$bXx&Wa|efSQw)l@qfX zJfR^6Scwk=Bte*8zNRn29xLUXZayGE)`!v5-L!NgynU;ym5{vD?KRi2hq7(N(N?H0 zLkmuQD)VH6cW~(gyc@C!kcc7b36{0Pj`4ffz+Rn`euK?hXvQMo3nl`-pt-Oy0)yBv zQ$m=S5}<1c3|51=53p}Pn^168CcK7W>xYD_q;7m8>Y4C5&c$3olNN;}8;ErYvFWim zZ0go^f~!#X21s!W%w-)pnQrh#!PVa!jU(#{4ArPe&eZDbxT_7Ue!w-1AnLi%le7A( z`DMdAeqRDvf0L`2pw0^tvrk#O@Zcl3(*y1v0`j_!1MIeoSsUrGj90jpS^nEjNcZ&)VV$&sek=QH(KS8NMoL|FrU(ojiq;iJ7MUjcV zUWUF%%5wA#aJBMS^erzxAQ4?D#U`^FdTkEH*={_9V*MVp^;I_F8dYQY=@#}Tq)OdZ zAK6zDn>{w`g(H~P`pkxZpW{#1$Lxk?o_s{E;a7aiWvP8$( z#(O7{-nA0!UOV<%*bQL;?0d>RYN?_y#)9%PnTd_FQE0f>Jz)*9N3=lKby^WA1<=YJ z6#F(gTdb1Ot`CIu1YyyiA#8a!5G%fo>y-fzQZGZQQX;~NOmqswiY0QgK}m4aPo{9S zMwH8u$}?Q;t~GFF^yF8Qh#z$) zbrw&hc4N}q!38G5WLB5{oI`V-7p$#U#&_0u@q$TlEk;8IkDQ*Z@1S$cRAZUpx3ak324i|Q9);Kii!uBu3BW{%%%S9l zmEEdD@M1ERailYlh8&5x;ZWmC)DVvJ7Bw=C#N2SG@pTykQKsLQF(4r-OQMbWv)s@H zN0|a+0!Cy7i~^Wa8BD1NepgK9us&kWzp4PmkKx#VDPxnv?a0`M!xd$0B1|RM{E29i zQ~gvl4X3JzCiBLsFr`wqic#KH+(y|MfjyNmCCw_+L<*R?3{1%ZO-#0^Bbk_EULocNd4mG|?4e?TP`k|Myelg8jf*i@@O`XDH7Vu0=zVZl@ z|4(KC`Mlrfyu#$k>4!{yO6DVzujQKmEShBUO&HU|O3jmPQZY8s-^WrPd>hRtc=7sgpl|5Kd}e~tPbj~m*Kg`Bj~V|5 zm_4(_9BuIB{F0^cvDP~;5x`9gx@6Br~7%$*~VU^;$BrZACUhWzot+n1`>PoDPnbr)Cb z$V<6p8bWcI(oHsx3vZKxYR&5;5a~>wBo3Lvvl7_Hh4gb0(vw5}jI$Ae^~Y$&TxpDY zu0FEe!)a`!kxt?wKPrxt^1Q5+SK9EUM2li8w*6q>B$bSSUYGAsbMoDc{~pZ zWh^0&{603+c#|5kwSR>g8383l9co;aF)A42n=%F@5KvFFNkB`owYteHdgdkws4oOG z00CvGjs*1IKn~n|>^m|x*Y`acJ6oTOEh%oU`LSqnga0SdG#h*%n)2ZyBcNs#k0YSf z;RgQ-O(J`?xQejD*VuQkqaRSuysp*NiMWp0*N;>G3Y!T6dYD^!((TEIU&I_s{99rC z$%&}G%h4wa9LMs_{n07*pf8yZYfpx4`i5=N5$nhC6(;-UCtNr^+Atsd7EOML?|6$k zyrm<2KP=~6X({WIx=iYsThgh1CrY@MMONFg(%)*_?U=7CMNF8^G(BZXzv}xq`u-Fo J%J`}J{|{6cWh(#x literal 0 HcmV?d00001 diff --git a/test/repository/__pycache__/test_session_repository.cpython-310-pytest-8.3.4.pyc b/test/repository/__pycache__/test_session_repository.cpython-310-pytest-8.3.4.pyc new file mode 100644 index 0000000000000000000000000000000000000000..18afc948e3c82b8762c58c2c9abef01f39e854dd GIT binary patch literal 6305 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�kQ`b{hQoGu+)G^vkNjhw9 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 UserAnswerEntity: + return UserAnswerEntity( + session_id="session123", + quiz_id=str(ObjectId()), + user_id="user123", + answered_at=datetime.utcnow(), + answers=[ + AnswerItemEntity( + question_index=0, answer="B", is_correct=True, time_spent=10 + ) + ], + total_score=80, + total_correct=4, + ) + + +def test_create(repository): + dummy_entity = generate_dummy_answer_entity() + insert_result = MagicMock(inserted_id=ObjectId()) + repository.collection.insert_one.return_value = insert_result + + result = repository.create(dummy_entity) + + repository.collection.insert_one.assert_called_once() + assert isinstance(result, str) + + +def test_get_by_id_found(repository): + dummy_entity = generate_dummy_answer_entity() + data = dummy_entity.model_dump(by_alias=True) + data["_id"] = ObjectId() + + repository.collection.find_one.return_value = data + + result = repository.get_by_id(str(data["_id"])) + + assert isinstance(result, UserAnswerEntity) + assert result.user_id == dummy_entity.user_id + assert result.quiz_id == dummy_entity.quiz_id + + +def test_get_by_id_not_found(repository): + repository.collection.find_one.return_value = None + + result = repository.get_by_id(str(ObjectId())) + + assert result is None + + +def test_get_by_user_and_quiz(repository): + quiz_id = ObjectId() + repository.collection.find.return_value = [ + {"_id": ObjectId(), "user_id": "u1", "quiz_id": quiz_id} + ] + + result = repository.get_by_user_and_quiz("u1", str(quiz_id)) + + repository.collection.find.assert_called_once_with( + {"user_id": "u1", "quiz_id": quiz_id} + ) + assert isinstance(result, list) + + +def test_get_by_user(repository): + dummy_data = [generate_dummy_answer_entity().model_dump(by_alias=True)] + repository.collection.find.return_value = dummy_data + + result = repository.get_by_user("user123") + + assert isinstance(result, list) + assert all(isinstance(item, UserAnswerEntity) for item in result) + + +def test_get_by_session(repository): + session_id = ObjectId() + repository.collection.find.return_value = [{"session_id": str(session_id)}] + + result = repository.get_by_session(str(session_id)) + + repository.collection.find.assert_called_once_with({"session_id": session_id}) + assert isinstance(result, list) + assert result[0]["session_id"] == str(session_id) + + +def test_delete_by_id(repository): + repository.collection.delete_one.return_value = MagicMock(deleted_count=1) + + result = repository.delete_by_id(str(ObjectId())) + + assert result is True diff --git a/test/repository/test_quiz_repository.py b/test/repository/test_quiz_repository.py new file mode 100644 index 0000000..8bbdefa --- /dev/null +++ b/test/repository/test_quiz_repository.py @@ -0,0 +1,171 @@ +import pytest +from unittest.mock import MagicMock +from bson import ObjectId +from datetime import datetime +from app.repositories import QuizRepository +from app.models.entities import QuizEntity + + +@pytest.fixture +def mock_db(): + return MagicMock() + + +@pytest.fixture +def repository(mock_db): + return QuizRepository(db=mock_db) + + +def generate_quiz_entity(**kwargs) -> QuizEntity: + return QuizEntity( + subject_id=kwargs.get("subject_id", "subject1"), + title=kwargs.get("title", "Kuis Sejarah Indonesia"), + description=kwargs.get( + "description", "Soal mengenai peristiwa penting Indonesia" + ), + is_public=kwargs.get("is_public", True), + date=kwargs.get("date", datetime.now()), + total_quiz=kwargs.get("total_quiz", 10), + limit_duration=kwargs.get("limit_duration", 30), + total_user_playing=kwargs.get("total_user_playing", 100), + question_listings=[], + author_id=kwargs.get("author_id", "guru123"), + ) + + +def test_create_quiz(repository): + quiz = generate_quiz_entity() + insert_result = MagicMock(inserted_id=ObjectId()) + repository.collection.insert_one.return_value = insert_result + + result = repository.create(quiz) + + repository.collection.insert_one.assert_called_once() + assert isinstance(result, str) + + +def test_get_by_id_found(repository): + quiz_id = ObjectId() + quiz_data = generate_quiz_entity().model_dump(by_alias=True) + quiz_data["_id"] = quiz_id + repository.collection.find_one.return_value = quiz_data + + result = repository.get_by_id(str(quiz_id)) + + assert isinstance(result, QuizEntity) + assert result.id == quiz_id + + +def test_get_by_id_not_found(repository): + repository.collection.find_one.return_value = None + + result = repository.get_by_id(str(ObjectId())) + + assert result is None + + +def test_search_by_title_or_category(repository): + mock_cursor = MagicMock() + mock_cursor.skip.return_value = mock_cursor + mock_cursor.limit.return_value = [generate_quiz_entity().model_dump(by_alias=True)] + repository.collection.find.return_value = mock_cursor + + result = repository.search_by_title_or_category( + keyword="Indonesia", + subject_id=None, + page=1, + page_size=10, + ) + + assert len(result) == 1 + assert isinstance(result[0], QuizEntity) + + +def test_count_by_search(repository): + repository.collection.count_documents.return_value = 3 + + result = repository.count_by_search("sejarah") + + assert result == 3 + + +def test_get_by_ids(repository): + qid1, qid2 = ObjectId(), ObjectId() + data = [generate_quiz_entity().model_dump(by_alias=True) for _ in range(2)] + data[0]["_id"] = qid1 + data[1]["_id"] = qid2 + repository.collection.find.return_value = data + + result = repository.get_by_ids([str(qid1), str(qid2)]) + + assert result is not None + assert all(isinstance(q, QuizEntity) for q in result) + + +def test_get_by_user_id(repository): + mock_cursor = MagicMock() + mock_cursor.skip.return_value = mock_cursor + mock_cursor.limit.return_value = [generate_quiz_entity().model_dump(by_alias=True)] + repository.collection.find.return_value = mock_cursor + + result = repository.get_by_user_id("guru123") + + assert isinstance(result, list) + assert isinstance(result[0], QuizEntity) + + +def test_get_all(repository): + mock_cursor = MagicMock() + mock_cursor.skip.return_value = mock_cursor + mock_cursor.limit.return_value = [generate_quiz_entity().model_dump(by_alias=True)] + repository.collection.find.return_value = mock_cursor + + result = repository.get_all() + + assert len(result) == 1 + assert isinstance(result[0], QuizEntity) + + +def test_update(repository): + repository.collection.update_one.return_value = MagicMock(modified_count=1) + + result = repository.update(str(ObjectId()), {"title": "Update Title"}) + + assert result is True + + +def test_update_user_playing(repository): + repository.collection.update_one.return_value = MagicMock(modified_count=1) + + result = repository.update_user_playing(str(ObjectId()), 123) + + assert result is True + + +def test_delete(repository): + repository.collection.delete_one.return_value = MagicMock(deleted_count=1) + + result = repository.delete(str(ObjectId())) + + assert result is True + + +def test_count_by_user_id(repository): + repository.collection.count_documents.return_value = 7 + + result = repository.count_by_user_id("guru123") + + assert result == 7 + + +def test_get_top_played_quizzes(repository): + mock_cursor = MagicMock() + mock_cursor.sort.return_value = mock_cursor + mock_cursor.skip.return_value = mock_cursor + mock_cursor.limit.return_value = [generate_quiz_entity().model_dump(by_alias=True)] + repository.collection.find.return_value = mock_cursor + + result = repository.get_top_played_quizzes() + + assert isinstance(result, list) + assert isinstance(result[0], QuizEntity) diff --git a/test/repository/test_session_repository.py b/test/repository/test_session_repository.py new file mode 100644 index 0000000..590f411 --- /dev/null +++ b/test/repository/test_session_repository.py @@ -0,0 +1,116 @@ +import pytest +from unittest.mock import MagicMock +from bson import ObjectId +from datetime import datetime +from app.repositories import SessionRepository +from app.models.entities import SessionEntity + + +@pytest.fixture +def mock_db(): + return MagicMock() + + +@pytest.fixture +def repository(mock_db): + return SessionRepository(db=mock_db) + + +def generate_session_entity() -> SessionEntity: + return SessionEntity( + session_code="ABC123", + quiz_id="quiz1", + host_id="user1", + created_at=datetime.now(), + started_at=None, + ended_at=None, + is_active=True, + participan_limit=5, + participants=["user1"], + current_question_index=0, + ) + + +def test_insert_session(repository): + session = generate_session_entity() + insert_result = MagicMock(inserted_id=ObjectId()) + repository.collection.insert_one.return_value = insert_result + + result = repository.insert(session) + + repository.collection.insert_one.assert_called_once() + assert isinstance(result, str) + + +def test_find_by_session_id_found(repository): + session = generate_session_entity() + doc = session.model_dump(by_alias=True) + repository.collection.find_one.return_value = doc + + result = repository.find_by_session_id(session_id=doc["_id"]) + + assert isinstance(result, SessionEntity) + assert result.session_code == "ABC123" + + +def test_find_by_session_id_not_found(repository): + repository.collection.find_one.return_value = None + + result = repository.find_by_session_id("nonexistent_id") + + assert result is None + + +def test_find_by_session_code_found(repository): + session = generate_session_entity() + doc = session.model_dump(by_alias=True) + repository.collection.find_one.return_value = doc + + result = repository.find_by_session_code("ABC123") + + assert isinstance(result, SessionEntity) + assert result.quiz_id == "quiz1" + + +def test_update_session(repository): + repository.collection.update_one.return_value = MagicMock(modified_count=1) + + update_data = {"is_active": False} + result = repository.update("session123", update_data) + + repository.collection.update_one.assert_called_once_with( + {"_id": "session123"}, {"$set": update_data} + ) + assert result is True + + +def test_add_participant(repository): + repository.collection.update_one.return_value = MagicMock(modified_count=1) + + result = repository.add_participant("session123", "user999") + + repository.collection.update_one.assert_called_once_with( + {"_id": "session123"}, {"$addToSet": {"participants": "user999"}} + ) + assert result is True + + +def test_delete_session(repository): + repository.collection.delete_one.return_value = MagicMock(deleted_count=1) + + result = repository.delete("session123") + + repository.collection.delete_one.assert_called_once_with({"_id": "session123"}) + assert result is True + + +def test_list_active_sessions(repository): + doc = generate_session_entity().model_dump(by_alias=True) + repository.collection.find.return_value = [doc] + + result = repository.list_active_sessions() + + repository.collection.find.assert_called_once_with({"is_active": True}) + assert len(result) == 1 + assert isinstance(result[0], SessionEntity) + assert result[0].is_active is True diff --git a/test/repository/test_subject_repository.py b/test/repository/test_subject_repository.py new file mode 100644 index 0000000..16e5541 --- /dev/null +++ b/test/repository/test_subject_repository.py @@ -0,0 +1,139 @@ +import pytest +from unittest.mock import MagicMock +from bson import ObjectId +from app.repositories.subject_repository import SubjectRepository +from app.models.entities import SubjectEntity + + +@pytest.fixture +def mock_db(): + return MagicMock() + + +@pytest.fixture +def repository(mock_db): + return SubjectRepository(db=mock_db) + + +def generate_subject(name, short_name, desc, icon="") -> SubjectEntity: + return SubjectEntity(name=name, short_name=short_name, description=desc, icon=icon) + + +def test_create_subject(repository): + subject = generate_subject( + name="Sejarah Indonesia", + short_name="SEJARAH", + desc="Mempelajari peristiwa dan tokoh penting dalam sejarah nasional.", + ) + insert_result = MagicMock(inserted_id=ObjectId()) + repository.collection.insert_one.return_value = insert_result + + result = repository.create(subject) + + repository.collection.insert_one.assert_called_once() + assert isinstance(result, str) + + +def test_get_all_subjects(repository): + mock_data = [ + generate_subject( + "Biologi", + "BIO", + "Ilmu yang mempelajari makhluk hidup dan lingkungannya.", + ).model_dump(by_alias=True), + generate_subject( + "Fisika", + "FIS", + "Mempelajari fenomena alam seperti gaya, energi, dan gerak.", + ).model_dump(by_alias=True), + ] + repository.collection.find.return_value = mock_data + + result = repository.get_all() + + assert len(result) == 2 + assert result[0].name == "Biologi" + assert result[1].short_name == "FIS" + + +def test_get_by_id_valid(repository): + oid = ObjectId() + doc = generate_subject( + "Geografi", + "GEO", + "Studi tentang lokasi, wilayah, dan interaksi manusia-lingkungan.", + ).model_dump(by_alias=True) + doc["_id"] = oid + repository.collection.find_one.return_value = doc + + result = repository.get_by_id(str(oid)) + + assert isinstance(result, SubjectEntity) + assert result.name == "Geografi" + assert result.id == oid + + +def test_get_by_id_invalid(repository): + result = repository.get_by_id("invalid_id") + assert result is None + + +def test_get_by_ids_mixed(repository): + oid1 = ObjectId() + oid2 = ObjectId() + ids = [str(oid1), "invalid_id", str(oid2)] + + mock_docs = [ + { + **generate_subject( + "Kimia", + "KIM", + "Ilmu tentang zat dan reaksinya", + ).model_dump(by_alias=True), + "_id": oid1, + }, + { + **generate_subject( + "Ekonomi", + "EKO", + "Analisis produksi, distribusi, dan konsumsi", + ).model_dump(by_alias=True), + "_id": oid2, + }, + ] + repository.collection.find.return_value = mock_docs + + result = repository.get_by_ids(ids) + + assert len(result) == 2 + assert result[0].short_name == "KIM" + assert result[1].name == "Ekonomi" + + +def test_update_valid(repository): + oid = ObjectId() + repository.collection.update_one.return_value = MagicMock(modified_count=1) + + result = repository.update(str(oid), {"description": "Updated Description"}) + + assert result is True + + +def test_update_invalid(repository): + result = repository.update("invalid_object_id", {"name": "Something"}) + + assert result is False + + +def test_delete_valid(repository): + oid = ObjectId() + repository.collection.delete_one.return_value = MagicMock(deleted_count=1) + + result = repository.delete(str(oid)) + + assert result is True + + +def test_delete_invalid(repository): + result = repository.delete("invalid_object_id") + assert result is False diff --git a/test/repository/test_user_repository.py b/test/repository/test_user_repository.py new file mode 100644 index 0000000..82f8414 --- /dev/null +++ b/test/repository/test_user_repository.py @@ -0,0 +1,155 @@ +import pytest +from unittest.mock import MagicMock +from bson import ObjectId +from datetime import datetime +from app.repositories.user_repository import UserRepository +from app.models.entities import UserEntity + + +@pytest.fixture +def mock_db(): + return MagicMock() + + +@pytest.fixture +def user_repository(mock_db): + return UserRepository(db=mock_db) + + +def test_get_all_users(user_repository): + mock_users = [ + { + "_id": ObjectId(), + "email": "a@example.com", + "name": "A", + "password": "pass1", + "locale": "id-ID", + }, + { + "_id": ObjectId(), + "email": "b@example.com", + "name": "B", + "password": "pass2", + "locale": "id-ID", + }, + ] + user_repository.collection.find.return_value = mock_users + + result = user_repository.get_all_users() + + assert len(result) == 2 + assert all(isinstance(user, UserEntity) for user in result) + assert result[0].email == "a@example.com" + assert result[1].name == "B" + + +def test_get_user_by_email_found(user_repository): + mock_user = { + "_id": ObjectId(), + "email": "john@example.com", + "name": "John Doe", + "password": "hashed", + "birth_date": datetime(2000, 1, 1), + "locale": "en-US", + "phone": "08123456789", + } + user_repository.collection.find_one.return_value = mock_user + + result = user_repository.get_user_by_email("john@example.com") + + assert isinstance(result, UserEntity) + assert result.email == "john@example.com" + assert result.name == "John Doe" + + +def test_get_user_by_email_not_found(user_repository): + user_repository.collection.find_one.return_value = None + + result = user_repository.get_user_by_email("notfound@example.com") + + assert result is None + + +def test_get_user_by_id_found(user_repository): + user_id = ObjectId() + mock_user = { + "_id": user_id, + "email": "jane@example.com", + "name": "Jane", + "password": "hashed", + "birth_date": datetime(1990, 1, 1), + "locale": "en-US", + "phone": "089999999", + } + user_repository.collection.find_one.return_value = mock_user + + result = user_repository.get_user_by_id(str(user_id)) + + assert isinstance(result, UserEntity) + assert str(result.id) == str(user_id) + assert result.name == "Jane" + + +def test_get_by_google_id_found(user_repository): + mock_user = { + "_id": ObjectId(), + "google_id": "google-123", + "email": "google@example.com", + "name": "Google User", + "locale": "en-US", + } + user_repository.collection.find_one.return_value = mock_user + + result = user_repository.get_by_google_id("google-123") + + assert isinstance(result, UserEntity) + assert result.google_id == "google-123" + assert result.email == "google@example.com" + + +def test_insert_user(user_repository): + user_entity = UserEntity( + name="Test", + email="test@example.com", + password="123", + birth_date=datetime(2000, 1, 1), + phone="081111111", + locale="id-ID", + ) + mock_insert_result = MagicMock(inserted_id=ObjectId()) + user_repository.collection.insert_one.return_value = mock_insert_result + + result = user_repository.insert_user(user_entity) + + user_repository.collection.insert_one.assert_called_once() + assert isinstance(result, str) + + +def test_update_user(user_repository): + user_id = str(ObjectId()) + mock_result = MagicMock(modified_count=1) + user_repository.collection.update_one.return_value = mock_result + + result = user_repository.update_user(user_id, {"name": "Updated Name"}) + + assert result is True + + +def test_update_user_field(user_repository): + user_id = str(ObjectId()) + mock_result = MagicMock(modified_count=1) + user_repository.collection.update_one.return_value = mock_result + + result = user_repository.update_user_field(user_id, "phone", "0822334455") + + assert result is True + + +def test_delete_user(user_repository): + user_id = str(ObjectId()) + mock_result = MagicMock(deleted_count=1) + user_repository.collection.delete_one.return_value = mock_result + + result = user_repository.delete_user(user_id) + + assert result is True