تست واحد فلوتر: از موارد ضروری تا سناریوهای پیچیده


علاقه به فلاتر در حد یک است اوج تمام دوران-و خیلی وقته مونده. SDK منبع باز Google با اندروید، iOS، macOS، وب، ویندوز و لینوکس سازگار است. یک پایگاه کد فلاتر از همه آنها پشتیبانی می کند. و تست واحد در ارائه یک برنامه Flutter سازگار و قابل اعتماد، با بهبود پیشگیرانه کیفیت کد قبل از مونتاژ، از خطاها، نقص ها و نقص ها اطمینان حاصل می کند.

در این آموزش، ما بهینه‌سازی‌های گردش کار را برای تست واحد فلاتر به اشتراک می‌گذاریم، یک تست واحد فلاتر را نشان می‌دهیم، سپس به موارد و کتابخانه‌های پیچیده‌تر تست فلاتر می‌رویم.

جریان تست واحد در فلوتر

ما تست واحد را در Flutter به همان روشی که در سایر پشته های فناوری انجام می دهیم پیاده سازی می کنیم:

  1. کد را ارزیابی کنید
  2. تمسخر داده را تنظیم کنید.
  3. گروه(های) آزمون را تعریف کنید.
  4. امضا(های) تابع آزمون را برای هر گروه آزمایشی تعریف کنید.
  5. تست ها را بنویسید

برای نشان دادن تست واحد، من یک را آماده کرده ام نمونه پروژه فلاتر و شما را تشویق به استفاده و تست کد در اوقات فراغت خود می کند. پروژه از یک API خارجی برای واکشی و نمایش لیستی از دانشگاه هایی که می توانیم بر اساس کشور فیلتر کنیم.

چند نکته در مورد نحوه عملکرد Flutter: این چارچوب تست را با بارگذاری خودکار تسهیل می کند flutter_test کتابخانه زمانی که یک پروژه ایجاد می شود. این کتابخانه فلاتر را قادر می سازد تا تست های واحد را بخواند، اجرا کند و تجزیه و تحلیل کند. فلاتر نیز به صورت خودکار ایجاد می کند test پوشه ای که در آن تست ها ذخیره می شوند. اجتناب از تغییر نام و/یا جابجایی آن بسیار مهم است test پوشه، زیرا عملکرد آن و در نتیجه توانایی ما برای اجرای آزمایش‌ها را از بین می‌برد. گنجاندن آن نیز ضروری است _test.dart در نام فایل های آزمایشی ما، زیرا این پسوند نحوه تشخیص فایل های آزمایشی توسط Flutter است.

تست ساختار دایرکتوری

برای ترویج تست واحد در پروژه خود، MVVM را با معماری تمیز و تزریق وابستگی (DI)، همانطور که در نام های انتخاب شده برای زیرپوشه های کد منبع مشهود است. ترکیبی از اصول MVVM و DI جداسازی نگرانی ها را تضمین می کند:

  1. هر کلاس پروژه از یک هدف واحد پشتیبانی می کند.
  2. هر تابع در یک کلاس فقط محدوده خود را برآورده می کند.

ما یک فضای ذخیره سازی سازمان یافته برای فایل های آزمایشی که می نویسیم ایجاد خواهیم کرد، سیستمی که در آن گروه هایی از تست ها “خانه هایی” به راحتی قابل شناسایی خواهند داشت. با توجه به نیاز فلاتر به مکان یابی تست ها در داخل test پوشه، بیایید ساختار پوشه کد منبع خود را در زیر بازتاب دهیم test. سپس، وقتی تستی می نویسیم، آن را در زیر پوشه مناسب ذخیره می کنیم: همانطور که جوراب های تمیز در کشوی جوراب کمد شما و پیراهن های تا شده در کشوی پیراهن می روند، تست های واحد Model کلاس ها در پوشه ای به نام model، مثلا.

ساختار پوشه فایل با دو پوشه سطح اول: lib و test.  تو در تو در زیر lib ما پوشه ویژگی ها را داریم، تو در تو universities_feed و بیشتر تو در تو داده ها هستند.  پوشه داده حاوی مخزن و پوشه منبع است.  در زیر پوشه منبع، پوشه شبکه قرار دارد.  در زیر شبکه، پوشه‌های نقطه پایانی و مدل، به علاوه فایل University_remote_data_source.dart وجود دارد.  در پوشه model فایل api_university_model.dart قرار دارد.  در همان سطح پوشه universities_feed که قبلاً ذکر شد، پوشه های دامنه و ارائه قرار دارند.  در زیر دامنه، پوشه usecase قرار دارد.  در زیر نمایش، مدل‌ها و پوشه‌های صفحه نمایش قرار دارند.  ساختار پوشه آزمایشی که قبلاً ذکر شد از ساختار lib تقلید می کند.  در زیر پوشه تست، پوشه unit_test قرار دارد که حاوی پوشه universities_feed است.  ساختار پوشه آن مانند پوشه universities_feed فوق است که دارای فایل های دارت است "_تست" به نام آنها اضافه شده است.
ساختار پوشه آزمایشی پروژه که ساختار کد منبع را منعکس می کند

اتخاذ این فایل سیستم شفافیت را در پروژه ایجاد می کند و به تیم یک راه آسان برای مشاهده اینکه کدام بخش از کد ما دارای تست های مرتبط است را می دهد.

ما اکنون آماده هستیم تا آزمایش واحد را وارد عمل کنیم.

تست واحد فلوتر ساده

ما با شروع خواهیم کرد model کلاس ها (در data لایه کد منبع) و مثال ما را محدود می کند که فقط یک مورد را شامل شود model کلاس، ApiUniversityModel. این کلاس دارای دو عملکرد است:

  • مدل خود را با تمسخر شی JSON با a مقداردهی کنید Map.
  • را بسازید University مدل داده.

برای آزمایش هر یک از عملکردهای مدل، مراحل جهانی که قبلاً توضیح داده شد را سفارشی می کنیم:

  1. کد را ارزیابی کنید
  2. راه اندازی تمسخر داده: ما پاسخ سرور به تماس API خود را تعریف می کنیم.
  3. گروه های آزمایشی را تعریف کنید: ما دو گروه آزمایشی خواهیم داشت، یکی برای هر تابع.
  4. امضای تابع آزمون را برای هر گروه آزمایشی تعریف کنید.
  5. تست ها را بنویسید

پس از ارزیابی کد خود، ما آماده هستیم تا هدف دوم خود را به انجام برسانیم: راه‌اندازی تمسخر داده‌ها برای دو عملکرد در داخل ApiUniversityModel کلاس

برای مسخره کردن تابع اول (مدل ما را با مسخره کردن JSON با a راه اندازی می کنیم Map) fromJson، ما دو را ایجاد می کنیم Map اشیاء برای شبیه سازی داده های ورودی برای تابع. ما همچنین دو معادل ایجاد خواهیم کرد ApiUniversityModel اشیاء برای نشان دادن نتیجه مورد انتظار تابع با ورودی ارائه شده.

برای تمسخر تابع دوم (ساخت University مدل داده)، toDomain، ما دو را ایجاد می کنیم University اشیاء، که نتیجه مورد انتظار پس از اجرای این تابع در نمونه قبلی هستند ApiUniversityModel اشیاء:

void main() {
    Map<String, dynamic> apiUniversityOneAsJson = {
        "alpha_two_code": "US",
        "domains": ["marywood.edu"],
        "country": "United States",
        "state-province": null,
        "web_pages": ["
        "name": "Marywood University"
    };
    ApiUniversityModel expectedApiUniversityOne = ApiUniversityModel(
        alphaCode: "US",
        country: "United States",
        state: null,
        name: "Marywood University",
        websites: ["
        domains: ["marywood.edu"],
    );
    University expectedUniversityOne = University(
        alphaCode: "US",
        country: "United States",
        state: "",
        name: "Marywood University",
        websites: ["
        domains: ["marywood.edu"],
    );
 
    Map<String, dynamic> apiUniversityTwoAsJson = {
        "alpha_two_code": "US",
        "domains": ["lindenwood.edu"],
        "country": "United States",
        "state-province":"MJ",
        "web_pages": null,
        "name": "Lindenwood University"
    };
    ApiUniversityModel expectedApiUniversityTwo = ApiUniversityModel(
        alphaCode: "US",
        country: "United States",
        state:"MJ",
        name: "Lindenwood University",
        websites: null,
        domains: ["lindenwood.edu"],
    );
    University expectedUniversityTwo = University(
        alphaCode: "US",
        country: "United States",
        state: "MJ",
        name: "Lindenwood University",
        websites: [],
        domains: ["lindenwood.edu"],
    );
}

در مرحله بعد، برای اهداف سوم و چهارم، زبان توصیفی را برای تعریف گروه‌های آزمایشی و امضاهای تابع آزمایشی اضافه می‌کنیم:

    void main() {
    // Previous declarations
        group("Test ApiUniversityModel initialization from JSON", () {
            test('Test using json one', () {});
            test('Test using json two', () {});
        });
        group("Test ApiUniversityModel toDomain", () {
            test('Test toDomain using json one', () {});
            test('Test toDomain using json two', () {});
        });
}

ما امضای دو تست را برای بررسی تعریف کرده ایم fromJson تابع، و دو برای بررسی toDomain عملکرد.

برای تحقق هدف پنجم و نوشتن تست‌ها، از عبارت استفاده می‌کنیم کتابخانه flutter_test‘s expect روش مقایسه نتایج توابع در برابر انتظارات ما:

void main() {
    // Previous declarations
        group("Test ApiUniversityModel initialization from json", () {
            test('Test using json one', () {
                expect(ApiUniversityModel.fromJson(apiUniversityOneAsJson),
                    expectedApiUniversityOne);
            });
            test('Test using json two', () {
                expect(ApiUniversityModel.fromJson(apiUniversityTwoAsJson),
                    expectedApiUniversityTwo);
            });
        });

        group("Test ApiUniversityModel toDomain", () {
            test('Test toDomain using json one', () {
                expect(ApiUniversityModel.fromJson(apiUniversityOneAsJson).toDomain(),
                    expectedUniversityOne);
            });
            test('Test toDomain using json two', () {
                expect(ApiUniversityModel.fromJson(apiUniversityTwoAsJson).toDomain(),
                    expectedUniversityTwo);
            });
        });
}

پس از انجام پنج هدف خود، اکنون می‌توانیم تست‌ها را از IDE یا از خط فرمان اجرا کنیم.

اسکرین شات نشان می‌دهد که از هر پنج آزمون، پنج آزمون قبول شده‌اند.  هدر می‌خواند: اجرا: تست‌ها در api_university_model_test.dart.  پانل سمت چپ صفحه نمایش می‌دهد: نتایج آزمایش --- بارگیری api_university_model_test.dart---api_university_model_test.dart---تست مقداردهی اولیه ApiUniversityModel از json---تست با استفاده از json one---تست با استفاده از json two---Tests ApiUniversityModel toD --- تست toDomain با استفاده از json one --- تست toDomain با استفاده از json two.  پانل سمت راست صفحه نشان می دهد: تست های انجام شده: پنج تست از پنج تست --- تست تست فلوتر/unit_test/universities_feed/data/source/network/model/api_university_model_test.dart

در یک ترمینال، ما می توانیم تمام تست های موجود در داخل را اجرا کنیم test پوشه با وارد کردن flutter test دستور دهید و ببینید که تست های ما با موفقیت انجام می شود.

از طرف دیگر، می‌توانیم یک آزمون یا گروه آزمایشی را با وارد کردن آن اجرا کنیم flutter test --plain-name "ReplaceWithName" دستور، جایگزین نام گروه آزمایشی یا آزمایشی ما ReplaceWithName.

واحد تست نقطه پایانی در فلوتر

پس از تکمیل یک تست ساده بدون وابستگی، بیایید یک مثال جالب تر را بررسی کنیم: ما آن را آزمایش می کنیم endpoint کلاس، که دامنه آن شامل:

  • اجرای یک تماس API با سرور.
  • تبدیل پاسخ API JSON به فرمت دیگری.

پس از ارزیابی کد خود، از آن استفاده خواهیم کرد کتابخانه flutter_test‘s setUp روش برای مقداردهی اولیه کلاس ها در گروه آزمایشی ما:

group("Test University Endpoint API calls", () {
    setUp(() {
        baseUrl = "
        dioClient = Dio(BaseOptions());
        endpoint = UniversityEndpoint(dioClient, baseUrl: baseUrl);
    });
}

برای درخواست شبکه به API ها، ترجیح می دهم از آن استفاده کنم کتابخانه مقاوم سازی، که بیشتر کدهای لازم را تولید می کند. برای تست صحیح UniversityEndpoint کلاس، ما به زور کتابخانه دیو– کدام Retrofit برای اجرای فراخوانی های API استفاده می کند — برای بازگرداندن نتیجه مورد نظر با تمسخر Dio رفتار کلاس از طریق یک آداپتور پاسخ سفارشی.

شبیه سازی رهگیر شبکه سفارشی

تمسخر به دلیل ساختن ما امکان پذیر است UniversityEndpoint کلاس از طریق DI. (اگر UniversityEndpoint کلاس باید a را مقداردهی اولیه کند Dio کلاس به خودی خود، هیچ راهی برای تمسخر رفتار کلاس وجود نخواهد داشت.)

به منظور تمسخر Dio رفتار کلاس، ما باید بدانیم Dio روش های مورد استفاده در Retrofit کتابخانه – اما ما دسترسی مستقیم به آن نداریم Dio. بنابراین، ما مسخره می کنیم Dio با استفاده از یک رهگیر پاسخ شبکه سفارشی:

class DioMockResponsesAdapter extends HttpClientAdapter {
  final MockAdapterInterceptor interceptor;

  DioMockResponsesAdapter(this.interceptor);

  @override
  void close({bool force = false}) {}

  @override
  Future<ResponseBody> fetch(RequestOptions options,
      Stream<Uint8List>? requestStream, Future? cancelFuture) {
    if (options.method == interceptor.type.name.toUpperCase() &&
        options.baseUrl == interceptor.uri &&
        options.queryParameters.hasSameElementsAs(interceptor.query) &&
        options.path == interceptor.path) {
      return Future.value(ResponseBody.fromString(
        jsonEncode(interceptor.serializableResponse),
        interceptor.responseCode,
        headers: {
          "content-type": ["application/json"]
        },
      ));
    }
    return Future.value(ResponseBody.fromString(
        jsonEncode(
              {"error": "Request doesn't match the mock interceptor details!"}),
        -1,
        statusMessage: "Request doesn't match the mock interceptor details!"));
  }
}

enum RequestType { GET, POST, PUT, PATCH, DELETE }

class MockAdapterInterceptor {
  final RequestType type;
  final String uri;
  final String path;
  final Map<String, dynamic> query;
  final Object serializableResponse;
  final int responseCode;

  MockAdapterInterceptor(this.type, this.uri, this.path, this.query,
      this.serializableResponse, this.responseCode);
}

اکنون که رهگیر را برای تمسخر پاسخ‌های شبکه خود ایجاد کرده‌ایم، می‌توانیم گروه‌های آزمایشی و امضاهای تابع آزمایشی خود را تعریف کنیم.

در مورد ما، ما فقط یک تابع برای آزمایش داریم (getUniversitiesByCountry، بنابراین ما فقط یک گروه آزمایشی ایجاد می کنیم. ما پاسخ تابع خود را در سه موقعیت آزمایش می کنیم:

  1. هست Dio تابع کلاس در واقع توسط فراخوانی شده است getUniversitiesByCountry?
  2. اگر درخواست API ما خطایی را برگرداند، چه اتفاقی می‌افتد؟
  3. اگر درخواست API ما نتیجه مورد انتظار را برگرداند، چه اتفاقی می‌افتد؟

در اینجا امضاهای گروه آزمایشی و تابع آزمایشی ما آمده است:

  group("Test University Endpoint API calls", () {

    test('Test endpoint calls dio', () async {});

    test('Test endpoint returns error', () async {});

    test('Test endpoint calls and returns 2 valid universities', () async {});
  });

ما آماده ایم تا تست های خود را بنویسیم. برای هر مورد آزمایشی، یک نمونه از DioMockResponsesAdapter با پیکربندی مربوطه:

group("Test University Endpoint API calls", () {
    setUp(() {
        baseUrl = "
        dioClient = Dio(BaseOptions());
        endpoint = UniversityEndpoint(dioClient, baseUrl: baseUrl);
    });

    test('Test endpoint calls dio', () async {
        dioClient.httpClientAdapter = _createMockAdapterForSearchRequest(
            200,
            [],
        );
        var result = await endpoint.getUniversitiesByCountry("us");
        expect(result, <ApiUniversityModel>[]);
    });

    test('Test endpoint returns error', () async {
        dioClient.httpClientAdapter = _createMockAdapterForSearchRequest(
            404,
            {"error": "Not found!"},
        );
        List<ApiUniversityModel>? response;
        DioError? error;
        try {
            response = await endpoint.getUniversitiesByCountry("us");
        } on DioError catch (dioError, _) {
            error = dioError;
        }
        expect(response, null);
        expect(error?.error, "Http status error [404]");
    });

    test('Test endpoint calls and returns 2 valid universities', () async {
        dioClient.httpClientAdapter = _createMockAdapterForSearchRequest(
            200,
            generateTwoValidUniversities(),
        );
        var result = await endpoint.getUniversitiesByCountry("us");
        expect(result, expectedTwoValidUniversities());
    });
});

اکنون که تست نقطه پایانی ما کامل شد، بیایید کلاس منبع داده خود را آزمایش کنیم، UniversityRemoteDataSource. قبلاً مشاهده کردیم که UniversityEndpoint کلاس بخشی از سازنده است UniversityRemoteDataSource({UniversityEndpoint? universityEndpoint})، که نشان دهنده آن است UniversityRemoteDataSource استفاده می کند UniversityEndpoint کلاس برای تکمیل دامنه خود، بنابراین این کلاسی است که ما آن را مسخره خواهیم کرد.

تمسخر با موکیتو

در مثال قبلی، ما به صورت دستی خود را مسخره کردیم Dio آداپتور درخواست مشتری با استفاده از یک سفارشی NetworkInterceptor. اینجا داریم کل کلاس را مسخره می کنیم. انجام این کار به صورت دستی – تمسخر یک کلاس و عملکردهای آن – زمان بر خواهد بود. خوشبختانه، کتابخانه های ساختگی برای مدیریت چنین موقعیت هایی طراحی شده اند و می توانند کلاس های ساختگی را با حداقل تلاش ایجاد کنند. بیایید استفاده کنیم کتابخانه موکیتو، کتابخانه استاندارد صنعت برای تمسخر در فلاتر.

برای تمسخر Mockito، ابتدا حاشیه نویسی را اضافه می کنیم@GenerateMocks([class_1,class_2,…])” قبل از کد آزمون – درست بالای کد void main() {} عملکرد. در حاشیه نویسی، لیستی از نام کلاس ها را به عنوان پارامتر (به جای class_1,class_2…).

بعد، فلاتر را اجرا می کنیم flutter pub run build_runner build دستوری که کد کلاس های ساختگی ما را در همان دایرکتوری تست تولید می کند. نام فایل ساختگی حاصل ترکیبی از نام فایل آزمایشی به علاوه خواهد بود .mocks.dart، جایگزین تست .dart پسوند. محتوای فایل شامل کلاس های ساختگی است که نام آنها با پیشوند شروع می شود Mock. مثلا، UniversityEndpoint تبدیل می شود MockUniversityEndpoint.

حالا ما وارد می کنیم university_remote_data_source_test.dart.mocks.dart (فایل ساختگی ما) به university_remote_data_source_test.dart (فایل تست).

سپس، در setUp عملکرد، ما مسخره می کنیم UniversityEndpoint با استفاده از MockUniversityEndpoint و مقداردهی اولیه UniversityRemoteDataSource کلاس:

import 'university_remote_data_source_test.mocks.dart';

@GenerateMocks([UniversityEndpoint])
void main() {
    late UniversityEndpoint endpoint;
    late UniversityRemoteDataSource dataSource;

    group("Test function calls", () {
        setUp(() {
            endpoint = MockUniversityEndpoint();
            dataSource = UniversityRemoteDataSource(universityEndpoint: endpoint);
        });
}

ما با موفقیت مسخره کردیم UniversityEndpoint و سپس ما را مقداردهی اولیه کرد UniversityRemoteDataSource کلاس اکنون ما آماده هستیم تا گروه های آزمایشی و امضاهای تابع آزمایشی خود را تعریف کنیم:

group("Test function calls", () {

  test('Test dataSource calls getUniversitiesByCountry from endpoint', () {});

  test('Test dataSource maps getUniversitiesByCountry response to Stream', () {});

  test('Test dataSource maps getUniversitiesByCountry response to Stream with error', () {});
});

با این کار، گروه‌های تست، و امضاهای تابع تست ما تنظیم می‌شوند. ما آماده نوشتن تست های واقعی هستیم.

اولین آزمایش ما بررسی می کند که آیا UniversityEndpoint تابع زمانی فراخوانی می شود که منبع داده واکشی اطلاعات کشور را آغاز کند. ما با تعریف نحوه واکنش هر کلاس در هنگام فراخوانی توابع آن شروع می کنیم. از آنجایی که ما آن را مسخره کردیم UniversityEndpoint کلاس، کلاسی است که ما با استفاده از آن با آن کار خواهیم کرد when( function_that_will_be_called ).then( what_will_be_returned ) ساختار کد

توابعی که ما آزمایش می کنیم ناهمزمان هستند (توابعی که a را برمی گرداند Future شی)، بنابراین ما از آن استفاده خواهیم کرد when(function name).thenanswer( (_) {modified function result} ) ساختار کد برای اصلاح نتایج ما.

برای بررسی اینکه آیا getUniversitiesByCountry تابع را فرا می خواند getUniversitiesByCountry عملکرد در داخل UniversityEndpoint کلاس، ما استفاده خواهیم کرد when(...).thenAnswer( (_) {...} ) مسخره کردن getUniversitiesByCountry عملکرد در داخل UniversityEndpoint کلاس:

when(endpoint.getUniversitiesByCountry("test"))
    .thenAnswer((realInvocation) => Future.value(<ApiUniversityModel>[]));

اکنون که پاسخ خود را مسخره کردیم، تابع منبع داده را فراخوانی می کنیم و با استفاده از آن بررسی می کنیم verify تابع – چه UniversityEndpoint تابع نامیده شد:

test('Test dataSource calls getUniversitiesByCountry from endpoint', () {
    when(endpoint.getUniversitiesByCountry("test"))
        .thenAnswer((realInvocation) => Future.value(<ApiUniversityModel>[]));

    dataSource.getUniversitiesByCountry("test");
    verify(endpoint.getUniversitiesByCountry("test"));
});

ما می‌توانیم از همان اصول برای نوشتن تست‌های اضافی استفاده کنیم که بررسی کند آیا عملکرد ما به درستی نتایج نقطه پایانی ما را به جریان‌های داده مربوطه تبدیل می‌کند یا خیر:

import 'university_remote_data_source_test.mocks.dart';

@GenerateMocks([UniversityEndpoint])
void main() {
    late UniversityEndpoint endpoint;
    late UniversityRemoteDataSource dataSource;

    group("Test function calls", () {
        setUp(() {
            endpoint = MockUniversityEndpoint();
            dataSource = UniversityRemoteDataSource(universityEndpoint: endpoint);
        });

        test('Test dataSource calls getUniversitiesByCountry from endpoint', () {
            when(endpoint.getUniversitiesByCountry("test"))
                    .thenAnswer((realInvocation) => Future.value(<ApiUniversityModel>[]));

            dataSource.getUniversitiesByCountry("test");
            verify(endpoint.getUniversitiesByCountry("test"));
        });

        test('Test dataSource maps getUniversitiesByCountry response to Stream',
                () {
            when(endpoint.getUniversitiesByCountry("test"))
                    .thenAnswer((realInvocation) => Future.value(<ApiUniversityModel>[]));

            expect(
                dataSource.getUniversitiesByCountry("test"),
                emitsInOrder([
                    const AppResult<List<University>>.loading(),
                    const AppResult<List<University>>.data([])
                ]),
            );
        });

        test(
                'Test dataSource maps getUniversitiesByCountry response to Stream with error',
                () {
            ApiError mockApiError = ApiError(
                statusCode: 400,
                message: "error",
                errors: null,
            );
            when(endpoint.getUniversitiesByCountry("test"))
                    .thenAnswer((realInvocation) => Future.error(mockApiError));

            expect(
                dataSource.getUniversitiesByCountry("test"),
                emitsInOrder([
                    const AppResult<List<University>>.loading(),
                    AppResult<List<University>>.apiError(mockApiError)
                ]),
            );
        });
    });
}

ما تعدادی تست واحد فلاتر را اجرا کرده ایم و رویکردهای مختلفی را برای تمسخر نشان داده ایم. من از شما دعوت می کنم به استفاده از من ادامه دهید نمونه پروژه فلاتر برای اجرای تست های اضافی

تست های واحد فلوتر: کلید شما برای UX برتر

اگر قبلاً تست واحد را در پروژه‌های فلاتر خود وارد کرده‌اید، این مقاله ممکن است گزینه‌های جدیدی را معرفی کرده باشد که می‌توانید به گردش کار خود تزریق کنید. در این آموزش، ما نشان دادیم که چقدر ساده است که آزمایش واحد را در پروژه بعدی فلاتر خود بگنجانید و چگونه با چالش‌های سناریوهای آزمایشی دقیق‌تر مقابله کنید. شاید دیگر هرگز نخواهید از تست های واحد در فلاتر رد شوید.

تیم تحریریه وبلاگ مهندسی Toptal از Matija Bečirević و Paul Hoskins برای بررسی نمونه کد و سایر محتوای فنی ارائه شده در این مقاله تشکر می کند.



منبع

Matthew Newman

Matthew Newman Matthew has over 15 years of experience in database management and software development, with a strong focus on full-stack web applications. He specializes in Django and Vue.js with expertise deploying to both server and serverless environments on AWS. He also works with relational databases and large datasets
[ Back To Top ]