- تست یکپارچه سازی پایگاه داده با استفاده از MariaDB برای جایگزینی MySql
- اجرای برنامه چند زبانه
- ذخیره فایل ها در برنامه و داده های مربوط به آنها در پایگاه داده
انواع تست
تست چیست؟ همانطور که ویکی می گوید: " آزمایش یا تست روشی برای مطالعه فرآیندهای اساسی یک سیستم با قرار دادن سیستم در موقعیت های مختلف و ردیابی تغییرات قابل مشاهده در آن است." به عبارت دیگر، این آزمایش عملکرد صحیح سیستم ما در شرایط خاص است. خوب، بیایید ببینیم چه نوع آزمایشی وجود دارد:-
تست واحد تست هایی است که وظیفه آنها آزمایش هر ماژول سیستم به صورت جداگانه است. مطلوب است که این قطعات حداقل قابل تقسیم از سیستم باشند، به عنوان مثال، ماژول ها.
-
تست سیستم یک تست سطح بالا برای آزمایش عملکرد یک قطعه بزرگتر از یک برنامه کاربردی یا سیستم به عنوان یک کل است.
-
تست رگرسیون آزمایشی است که برای بررسی اینکه آیا ویژگیهای جدید یا رفع اشکال بر عملکرد موجود برنامه تأثیر میگذارد و آیا باگهای قدیمی دوباره ظاهر میشوند یا خیر استفاده میشود.
-
تست عملکردی بررسی انطباق بخشی از برنامه با الزامات ذکر شده در مشخصات، داستان های کاربر و غیره است.
انواع تست عملکردی:
- تست "جعبه سفید" برای انطباق بخشی از برنامه با الزامات با دانش اجرای داخلی سیستم.
- تست "جعبه سیاه" برای انطباق بخشی از برنامه با الزامات بدون اطلاع از اجرای داخلی سیستم.
- تست عملکرد نوعی تست است که برای تعیین سرعت اجرای یک سیستم یا بخشی از آن تحت یک بار مشخص نوشته می شود.
- تست بار - تست هایی که برای بررسی پایداری سیستم تحت بارهای استاندارد و یافتن حداکثر پیک ممکن که برنامه در آن به درستی کار می کند طراحی شده است.
- تست استرس نوعی آزمایش است که برای بررسی عملکرد یک برنامه کاربردی تحت بارهای غیر استاندارد و تعیین حداکثر پیک ممکن که در آن سیستم خراب نمی شود، طراحی شده است.
- تست امنیتی - تست هایی که برای بررسی امنیت یک سیستم (از حملات هکرها، ویروس ها، دسترسی غیرمجاز به داده های محرمانه و سایر لذت های زندگی) استفاده می شود.
- تست محلی سازی ، تست بومی سازی برای یک برنامه کاربردی است.
- تست کاربردپذیری نوعی تست با هدف بررسی قابلیت استفاده، قابل فهم بودن، جذابیت و یادگیری برای کاربران است. همه اینها خوب به نظر می رسد، اما در عمل چگونه کار می کند؟ ساده است: از هرم آزمایشی مایک کوهن استفاده می شود: این یک نسخه ساده شده از هرم است: اکنون به قسمت های کوچکتر تقسیم شده است. اما امروز ما منحرف نخواهیم شد و ساده ترین گزینه را در نظر می گیریم.
-
تست های واحد - واحد مورد استفاده در لایه های مختلف برنامه، آزمایش کوچکترین منطق قابل تقسیم برنامه: به عنوان مثال، یک کلاس، اما اغلب یک روش. این تستها معمولاً سعی میکنند تا حد امکان از منطق خارجی جدا شوند، یعنی این توهم ایجاد کنند که بقیه برنامه در حالت استاندارد کار میکند.
همیشه باید تعداد زیادی از این تست ها (بیشتر از انواع دیگر) وجود داشته باشد، زیرا آنها قطعات کوچک را آزمایش می کنند و بسیار سبک وزن هستند و منابع زیادی را مصرف نمی کنند (منظور از منابع RAM و زمان است).
-
ادغام - تست یکپارچه سازی. قطعات بزرگتر سیستم را بررسی می کند، یعنی یا ترکیبی از چندین قطعه منطق (چند روش یا کلاس)، یا صحت کار با یک جزء خارجی است. معمولاً تعداد این تستها کمتر از تستهای واحد است، زیرا سنگینتر هستند.
به عنوان نمونه ای از تست های یکپارچه سازی، می توانید اتصال به پایگاه داده و بررسی اجرای صحیح روش های کار با آن را در نظر بگیرید .
-
UI - تست هایی که عملکرد رابط کاربری را بررسی می کنند. آنها منطق را در تمام سطوح برنامه تحت تأثیر قرار می دهند، به همین دلیل است که به آنها end-to-end نیز می گویند. به عنوان یک قاعده، تعداد بسیار کمتری از آنها وجود دارد، زیرا آنها سنگین ترین وزن هستند و باید مسیرهای ضروری (استفاده شده) را بررسی کنند.
در شکل بالا نسبت مساحت قسمت های مختلف مثلث را می بینیم: تقریباً همین نسبت در تعداد این تست ها در کار واقعی حفظ می شود.
امروز ما نگاهی دقیق تر به تست های پرکاربرد - تست های واحد خواهیم داشت، زیرا همه توسعه دهندگان جاوا که به خود احترام می گذارند باید بتوانند از آنها در سطح پایه استفاده کنند.
- ما در حال نوشتن آزمون خود هستیم.
- ما آزمایش را انجام می دهیم، چه قبول شده باشد یا نه (می بینیم که همه چیز قرمز است - نترسید: اینطوری باید باشد).
- ما کدی را اضافه می کنیم که باید این تست را برآورده کند (تست را اجرا کنید).
- ما کد را بازسازی می کنیم.
- مشخص کردن داده هایی که باید آزمایش شوند (تجهیزات).
- استفاده از کد تحت آزمایش ( فراخوانی متد تحت آزمایش ) .
- بررسی نتایج و مقایسه آنها با نتایج مورد انتظار.
assertEquals(Object expecteds, Object actuals)
- بررسی می کند که آیا اشیاء ارسال شده برابر هستند یا خیر.assertTrue(boolean flag)
- بررسی می کند که آیا مقدار ارسال شده درست است یا خیر.assertFalse(boolean flag)
- بررسی می کند که آیا مقدار ارسال شده false برمی گردد یا خیر.assertNull(Object object)
- بررسی می کند که آیا شیء تهی است یا خیر.assertSame(Object firstObject, Object secondObject)
- بررسی می کند که آیا مقادیر ارسال شده به یک شی اشاره دارد یا خیر.assertThat(T t, Matcher<T> matcher)
- بررسی می کند که آیا t شرایط مشخص شده در تطبیق را برآورده می کند یا خیر.
مفاهیم کلیدی تست واحد
پوشش تست (Code Coverage) یکی از ارزیابی های اصلی کیفیت تست برنامه است. این درصد کدی است که توسط تست ها پوشش داده شده است (0-100٪). در عمل، بسیاری از مردم این درصد را دنبال می کنند، که من با آن موافق نیستم، زیرا آنها شروع به اضافه کردن تست ها در جایی که نیازی ندارند، می کنند. به عنوان مثال، سرویس ما دارای عملیات استاندارد CRUD (ایجاد/دریافت/بهروزرسانی/حذف) بدون منطق اضافی است. این روش ها صرفاً واسطه هایی هستند که کار را به لایه ای که با مخزن کار می کند واگذار می کنند. در این شرایط، ما چیزی برای آزمایش نداریم: شاید این روش متدی را از تائو فراخوانی می کند، اما این جدی نیست. برای ارزیابی پوشش تست، معمولاً از ابزارهای اضافی استفاده می شود: JaCoCo، Cobertura، Clover، Emma و غیره. برای مطالعه دقیق تر این موضوع، چند مقاله مناسب را نگه دارید: TDD (توسعه مبتنی بر آزمایش) - توسعه آزمایش محور. در این رویکرد ابتدا تستی نوشته می شود که کد خاصی را بررسی می کند. معلوم می شود که آزمایش جعبه سیاه است: ما می دانیم در ورودی چه چیزی وجود دارد و می دانیم که در خروجی چه اتفاقی باید بیفتد. این از تکرار کد جلوگیری می کند. توسعه مبتنی بر تست با طراحی و توسعه تستها برای هر عملکرد کوچک برنامه آغاز میشود. در رویکرد TDD، ابتدا تستی ایجاد می شود که مشخص می کند و تأیید می کند که کد چه کاری انجام خواهد داد. هدف اصلی TDD این است که کد را واضح تر، ساده تر و بدون خطا کند. رویکرد شامل اجزای زیر است:مراحل تست
آزمون شامل سه مرحله است:محیط های تست
خب حالا بیایید به کار بپردازیم. چندین محیط تست (فریم ورک) برای جاوا وجود دارد. محبوب ترین آنها JUnit و TestNG هستند. برای بررسی ما از این موارد استفاده می کنیم: آزمون JUnit روشی است که در یک کلاس وجود دارد که فقط برای آزمایش استفاده می شود. یک کلاس معمولاً با کلاسی که آزمایش می کند با +Test در پایان نامگذاری می شود. به عنوان مثال، CarService → CarServiceTest. سیستم ساخت Maven به طور خودکار چنین کلاس هایی را در منطقه آزمایشی شامل می شود. در واقع به این کلاس کلاس تست می گویند. بیایید کمی حاشیه نویسی های اولیه را مرور کنیم: @Test - تعریف این روش به عنوان یک روش تست (در واقع روش مشخص شده با این حاشیه یک تست واحد است). @Before - متدی را که قبل از هر تست اجرا می شود علامت گذاری می کند. به عنوان مثال، پر کردن دادههای آزمون کلاس، خواندن دادههای ورودی و غیره @After - بالای متدی قرار میگیرد که بعد از هر آزمون فراخوانی میشود (پاک کردن دادهها، بازیابی مقادیر پیشفرض). @BeforeClass - در بالای روش قرار داده شده است - مشابه @Before. اما این متد فقط یک بار قبل از همه تست ها برای یک کلاس مشخص فراخوانی می شود و بنابراین باید ثابت باشد. برای انجام عملیات سنگین تر، مانند بلند کردن پایگاه داده آزمایشی استفاده می شود. @AfterClass برعکس @BeforeClass است: یک بار برای یک کلاس مشخص اجرا می شود، اما پس از تمام تست ها اجرا می شود. به عنوان مثال، برای پاکسازی منابع پایدار یا قطع ارتباط از پایگاه داده استفاده می شود. @Ignore - خاطرنشان می کند که روش زیر غیرفعال است و هنگام اجرای آزمایشات به طور کلی نادیده گرفته می شود. در موارد مختلفی استفاده می شود، مثلاً اگر روش پایه تغییر کرده باشد و زمانی برای انجام مجدد تست برای آن وجود نداشته باشد. در چنین مواردی، توصیه میشود که یک توضیح اضافه کنید - @Ignore ("برخی توضیحات"). @Test (مورد انتظار = Exception.class) - برای تست های منفی استفاده می شود. اینها تستهایی هستند که نحوه رفتار یک متد را در صورت بروز خطا بررسی میکنند، یعنی آزمون انتظار دارد که متد استثناهایی ایجاد کند. چنین روشی با حاشیه نویسی @Test نشان داده می شود، اما با یک خطا برای catch. @Test(timeout=100) - بررسی می کند که روش در حداکثر 100 میلی ثانیه اجرا شود. @Mock - یک کلاس روی یک فیلد برای تنظیم یک شی داده شده به عنوان mock استفاده می شود (این از کتابخانه Junit نیست، بلکه از Mockito است)، و اگر به آن نیاز داشته باشیم، رفتار mock را در یک موقعیت خاص تنظیم می کنیم. ، مستقیماً در روش تست. @RunWith(MockitoJUnitRunner.class) - متد بالای کلاس قرار می گیرد. این دکمه برای اجرای تست ها در آن است. Runner ها می توانند متفاوت باشند: به عنوان مثال، موارد زیر وجود دارد: MockitoJUnitRunner، JUnitPlatform، SpringRunner، و غیره). در JUnit 5، حاشیه نویسی @RunWith با حاشیه نویسی قدرتمندتر @ExtendWith جایگزین شد. بیایید به چند روش برای مقایسه نتایج نگاهی بیندازیم:assertThat(firstObject).isEqualTo(secondObject)
در اینجا من در مورد روش های اساسی صحبت کردم، زیرا بقیه انواع مختلفی از موارد بالا هستند.
تمرین تست
حال بیایید با استفاده از یک مثال خاص به مطالب بالا نگاه کنیم. ما روش را برای سرویس آزمایش خواهیم کرد - به روز رسانی. ما لایه dao را در نظر نخواهیم گرفت، زیرا این لایه پیش فرض ما است. بیایید یک شروع کننده برای تست ها اضافه کنیم:<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.2.2.RELEASE</version>
<scope>test</scope>
</dependency>
بنابراین، کلاس خدمات:
@Service
@RequiredArgsConstructor
public class RobotServiceImpl implements RobotService {
private final RobotDAO robotDAO;
@Override
public Robot update(Long id, Robot robot) {
Robot found = robotDAO.findById(id);
return robotDAO.update(Robot.builder()
.id(id)
.name(robot.getName() != null ? robot.getName() : found.getName())
.cpu(robot.getCpu() != null ? robot.getCpu() : found.getCpu())
.producer(robot.getProducer() != null ? robot.getProducer() : found.getProducer())
.build());
}
}
8 - شی به روز شده را از پایگاه داده 9-14 بکشید - شی را از طریق سازنده ایجاد کنید، اگر شی ورودی دارای فیلد است - آن را تنظیم کنید، اگر نه - آنچه در پایگاه داده است را رها کنید و به تست ما نگاه کنید:
@RunWith(MockitoJUnitRunner.class)
public class RobotServiceImplTest {
@Mock
private RobotDAO robotDAO;
private RobotServiceImpl robotService;
private static Robot testRobot;
@BeforeClass
public static void prepareTestData() {
testRobot = Robot
.builder()
.id(123L)
.name("testRobotMolly")
.cpu("Intel Core i7-9700K")
.producer("China")
.build();
}
@Before
public void init() {
robotService = new RobotServiceImpl(robotDAO);
}
1 - Runner 4 ما - با جایگزین کردن یک مدل ساختگی 11، سرویس را از لایه dao جدا کنید - یک موجودیت آزمایشی برای کلاس تنظیم کنید (آنی که به عنوان همستر آزمایشی استفاده خواهیم کرد) 22 - یک شی سرویس را تنظیم کنید که آن را آزمایش خواهیم کرد.
@Test
public void updateTest() {
when(robotDAO.findById(any(Long.class))).thenReturn(testRobot);
when(robotDAO.update(any(Robot.class))).then(returnsFirstArg());
Robot robotForUpdate = Robot
.builder()
.name("Vally")
.cpu("AMD Ryzen 7 2700X")
.build();
Robot resultRobot = robotService.update(123L, robotForUpdate);
assertNotNull(resultRobot);
assertSame(resultRobot.getId(),testRobot.getId());
assertThat(resultRobot.getName()).isEqualTo(robotForUpdate.getName());
assertTrue(resultRobot.getCpu().equals(robotForUpdate.getCpu()));
assertEquals(resultRobot.getProducer(),testRobot.getProducer());
}
در اینجا ما شاهد تقسیم واضح تست به سه بخش هستیم: 3-9 - تنظیم فیکسچر 11 - اجرای قسمت آزمایش شده 13-17 - بررسی نتایج جزئیات بیشتر: 3-4 - تنظیم رفتار برای moka dao 5 - تنظیم یک نمونه که ما در بالای استاندارد 11 خود را به روز خواهیم کرد - از روش استفاده کنید و نمونه حاصل را 13 در نظر بگیرید - بررسی کنید که صفر نباشد 14 - شناسه نتیجه و آرگومان های متد مشخص شده را بررسی کنید 15 - بررسی کنید که آیا نام به روز شده است یا خیر 16 - نگاه کنید در نتیجه توسط cpu 17 - از آنجایی که ما این را در قسمت نمونه بهروزرسانی تنظیم نکردهایم، باید ثابت بماند، بیایید آن را بررسی کنیم. بیایید راه اندازی کنیم: آزمایش سبز است، می توانید بازدم کنید)) بنابراین، بیایید خلاصه کنیم: آزمایش کیفیت کد را بهبود می بخشد و فرآیند توسعه را انعطاف پذیرتر و قابل اعتمادتر می کند. تصور کنید هنگام طراحی مجدد نرم افزار با صدها فایل کلاس چقدر باید تلاش کنیم. هنگامی که برای همه این کلاس ها تست های واحد نوشته شده است، می توانیم با اطمینان مجدداً آن را اصلاح کنیم. و مهمتر از همه، به ما کمک می کند تا به راحتی خطاها را در طول توسعه پیدا کنیم. بچه ها، امروز همه اینها برای من است: لایک کنید، نظر بنویسید)))
GO TO FULL VERSION