
خب یه بخش دیگه از روش های بهتر کار کردن با جنگو رو قصد دارم در اینجا با شما بررسی کنیم قبل از هرچیزی یه توضیح در مورد اسم این نمونه پست ها بدم شماره اول که بعد از s نوشته شده شماره پست هست شماره ای که بعد از ep نوشته شده تعداد پستایی که تا الان در مورد یه مبحث خواص پست گزاشتم
میتونید از اینجا : Django way (روشهای بهتر کار کردن با جنگو) پست قبلی رو بخونید
این مبحث هم به احتمال زیاد در چند بخش ادامه پیدا کنه
امروزه برنامه ها رشد خیلی زیادی کردن و در تولید یک برنامه باید سرعت در توسعه و stable بودن کد ها رو کنار هم پیاد کرد برای همین متدولوژی های مختلفی برای پیش بردن یک پروژه ارايه شده که در اکثر اونها تست کردن کد ها و coverage گرفتن از اونها حرف اول رو میزنه مسلما جنگو هم از این قضیه هم نقش خودش رو ایفا کرده و روش هایی برای آسون کردن تست نویسی درست کرده
من توی این پست از rest framework استفاده میکنم
خب بریم ببینیم که چطور یه تست کوچیک میشه برای api خودمون بنویسیم:
به فرض داریم :
# ./product/models.py from django.db import models class Product(models.model): name = models.CharField(max_length=250) description = models.TextField(max_length=250, blank=True, null=True) image = models.ImageField(blank=True, null=True) price = models.FloatField() # ./product/api/serializer.py from rest_framework import serializers from product.models import Product class ProductSerializer(serializers.ModelSerializer): class Meta: model = Prodcut fields = '__all__' # ./product/api/views.py from .serializer import ProductSerializer from from product.models import Product from rest_framework import viewsets class ProductViewSet(viewsets.ModelViewSet): serializer_class = ProductSerializer query_set = Product.objects.all() # ./prodcut/urls.py from rest_framework.routers import SimpleRouter from .api import views as api_views urlpatterns = [ ] product_router = SimpleRouter() product_router.register('product', api_views.ProductViewSet, basename='product') api_patterns = product_router.urls
خب حالا برنامه ما حاضره و در حالت عادی میخوایم تستش کنیم مسلما تستمون یه چیزی شبیه این میشه :
#./prodcut/tests.py from rest_framework.test import APITestCase class ProductTestView(APITestCase): @classmethod def setUpTestData(cls): cls.product_1 = Product.objects.create( name="Xbox one", description="i need xbox one please", price=800000000, ) cls.product_2 = Product.objects.create( name="PS4", description="i need Ps4 right now", price=3100000000, ) cls.product_3 = Product.objects.create( name="need for speed", description="need for speed most wanted", price=5000 ) # and.... def test_get_product_list(self): response = self.client.get(self.url) assert response.data['result'][0]['name']=="Xbox one" self.assertEqual(response.status_code, 200) self.assertEqual(response.data['count'],10)
خوب فکر کنم تا اینجاش فهمیدید چه زخمی خوردیم تازه برنامه ما کوچیک هست که تونستیم به همین مقدار کد تمومش کنیم( تازه عکسم من به دیتام اضافه نکردم چون واقعا دردسره) توی دنیای واقعی با دیتا های واقعی هیچ وقت همه چیز به سادگی دو تا فیلد توی مدلامون نیست...
کدای تستمون فوق العاده کثیف و بهم ریخته دیتا های تکراری و... اصلا یه وضعی که موقع دیدنش چشم آدم خون میاد. حالا فرض کن بچه های فرانت یه سری دیتا فیک بخوان تا کاراشون رو تست کنن دیگه نور علی نور
در این مواقع که ما نیاز به دیتای فیک داریم از تکنیک Database Mocking استفاده میکنیم
به نقل از این منبع : https://wiki.genexus.com/
تکنیک Database Mocking روشی برای شبیه سازی دیتابیس اصلی به همراه تعدادی رکورد برای انجام تست های مورد نیاز است
یکی از راحت ترین روش ها در پایتون برای Database Mocking استفاده از ماژول factory_boy و faker هست که کار را فوق العاده راحت میکنن همچنین ماژول factory_boy مدل های جنگو رو به صورت درونی ساپورت میکنه و توی داکیومنتش هم مثال های خوبی داره که راحت میتونی باهاش کارتون رو راه بندازید ماژول faker هم برای ساختن دیتا هم فیک و الکی از lorem_ipsum تا رمز و پسور فیک و حتی اسم شهر و کشور رو میشه باهاش تولید کرد البته factory_boy به صورت درونی ماژول faker رو هم ساپورت میکنه و نیازی نیست که به صورت مستقیم از faker استفاده بشه.
( یه فکت جالب در مورد ماژول factory_boy اینه که موقع ساخت این ماژول از تکنیک های یه ماژول قدیمی تر به توی زبان روبی به اسم factory_girl استفاده شده :)))) )
برای کار با این ماژول بهتره که توی پوشه اپمون یه فایل به اسم factories.py بسازیم و کدمون رو اینجوری بنویسیم:
#./product/factories.py import factory from factory import django from .models import Product class ProductFactory(django.DjangoModelFactory): name = factory.Faker('name') image = django.ImageField(color='blue') description = factory.Faker("text", max_nb_chars=200) price = factory.Faker("random_int", min=1000, max=9999999) class Meta: model = Product
خب حالا برای ساخت دیتا توی تستمون این کارو میکنیم :
#./prodcut/tests.py from rest_framework.test import APITestCase from .factories import ProductFactory class ProductTestView(APITestCase): @classmethod def setUpTestData(cls): cls.prodcuts = ProductFactory.create_batch(10) def test_get_product_list(self): response = self.client.get(self.url) assert response.data['result'][0]['name'] == self.product[0].name self.assertEqual(response.status_code, 200) self.assertEqual(response.data['count'],10)
همون طور که دیدید همه چیز راحت و زیبا و بسیار تمیز شد همه چیز سر جای خودشه و موقع عوض شدن api به خاطر به هم ریختن تست هامون گریه نمیکنیم :))
این اولین بخش از قسمتای کار با ماژول factory boy بود چند قسمت دیگه هم در موردشون حرف خواهم زد اگه دوست داشتید میتونید منو فالو کنید تا بقیه قسمت ها رو راحت پیدا کنید