Как я могу передать строку из одного модульного теста в другой в XCode? - PullRequest
0 голосов
/ 05 сентября 2018

У меня есть два модульных теста: testUserRegistration и testEmailConfirmation. Сначала запускается тест регистрации, я создаю уникальное электронное письмо для регистрации со случайным int, таким как autoTest1234@test.com или autoTest4928@test.com. В следующем тесте testEmailConfirmation мне нужно использовать то же имя пользователя, которое я создал в предыдущем тесте. Как я могу отправить его из одного метода испытаний в другой?

Ответы [ 4 ]

0 голосов
/ 05 сентября 2018

Кажется, вы не проводите модульное тестирование, а скорее тестирование интеграции или тестирование E2E (у меня есть догадка, что другой конец находится где-то на удаленном сервере). Это неплохая вещь, но давайте проясним терминологию :). Обратите внимание, что тесты E2E могут привести к ложным отрицаниям при значительном количестве условий, таких как временная недоступность сети, поэтому они не так надежны, как модульные тесты.

Делая абстракцию вышеупомянутого, вы можете переопределить класс setUp и сохранить в нем случайно сгенерированное письмо:

@interface MyTestCase()
@property (class) NSString *email;
@property (class) NSString *password;
@end

@implementation MyTestCase

+ (void)setUp {
    [super setUp];
    self.email = [self someRandomEmailGenerator];
    self.password = [self someRandomPasswordGenerator];
}

- (void)test_registration {
    // register with MyTestCase.email, MyTestCase.password
}

- (void)test_signup() {
    // signup with MyTestCase.email, MyTestCase.password
}

Обратите внимание, однако, как уже говорили другие, что не гарантируется, что регистрационный тест будет запущен до регистрации, поскольку Xcode имеет свою собственную логику. В настоящее время он подбирает тесты в алфавитном порядке, однако это может измениться, и параллелизация - это еще один аспект, который может вызвать у вас головную боль.

0 голосов
/ 05 сентября 2018

Вы можете достичь этого, создав подклассы XCTestCase.

Во время установки, если вы блокируете поток во время работы в сети, используя семафоры, а затем разблокируете поток, когда закончите сетевое событие.

Вы также можете добавить переменные в подкласс, чтобы иметь свободный доступ к переменным во всех ваших тестах.

Для цели C вам придется разделить файлы на .h и .m, чтобы иметь возможность подкласса вашего нового класса интеграционных тестов.

Пример Objective-C Реализация:

IntegrationTest.h

# import

@interface IntegrationTest : XCTestCase

// Add properties here you want your test cases to inherit.
// Added a user property as an example.
@property (nonatomic, strong, nullable) User *user;     

@end

IntegrationTest.m

@implementation IntegrationTest 

-(void)setUp {
    [super setUp];

    __weak IntegrationTest *wSelf = self;

    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

    [User registerUserWithEmail:@"SomeRandomEmail" completion:^(User *user, NSError * error) {
         wSelf.user = user;
         dispatch_semaphore_signal(semaphore);
    }];

    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

}

-(void)tearDown {
    [super tearDown];

    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

     // Do any networking related to tearing down such as deleting the user you just created
    [self.user deleteWithCompletion:^(NSError *error) { 
        dispatch_semaphore_signal(semaphore);
     }];

     dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

 }

Пример реализации Swift приведен ниже:

class IntegrationTest: XCTestCase {

     user: User?

     override func setUp() {
        super.setup()

        // Use a semaphore to block 
        let semaphore = DispatchSemaphore(value: 0)

        weak var wSelf = self

        registerUser(email: "SomeRandomEmail" ,completion: { (user, error) in 
           // Signal the semaphore for the tests to start running again
           // Do additional work, set variables, etc. here
           wSelf?.user = user
           semaphore.signal()
        })

        if semaphore.wait(timeout: DispatchTime.now() + .seconds(10)) == .timedOut {
           // If something goes wrong in the networking handle it here
           print("Networking failed")
        }    

     }

     override func tearDown() {

         let semaphore = DispatchSemaphore(value: 0)

         if let nonNilUser = user {
            // Delete the user or do additional networking for the teardown in the same manner
            user.delete(completion: { (error) in 
                // Do additional tear down work here
                semaphore.signal()
            }
         } else {
            semaphore.signal()
         }            

     }        

}

Все, что вам нужно сделать сейчас, это создать подкласс класса IntegrationTest и вызвать super.setUp() и super.tearDown() в Swift или [super setUp] и [super tearDown], если в Objective-C .

Я использовал эту структуру более двух лет для интеграционных тестов, которые требуют успешной работы в сети и аутентификации.

0 голосов
/ 05 сентября 2018

Вы можете попробовать использовать segue:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        let destinationVC: nameofdestinationVC = segue.destination as! nameofdestinationVC
        destinationVC.string = string var in other VC!
        
    }
0 голосов
/ 05 сентября 2018

Это не то, как вы должны думать о модульных тестах.

Прежде всего, вы не должны оценивать порядок тестирования: ваши тесты, скорее всего, будут выполняться в случайном порядке, решает Xcode, а не вы. Ваши тесты должны быть независимы друг от друга, и вы должны иметь возможность выполнять их в любом порядке. В Xcode 10 у нас будет тестовое распараллеливание, и вы действительно не хотите, чтобы они зависели друг от друга. Наконец, эта рандомизация хороша, чтобы убедиться, что ваш тест не работает только из-за побочного эффекта.

По сути, вам нужно два теста.

Первый выглядит так:

func testUserRegistration() {
  // Given [an email address / username]
  // When [you run the registration flow]
  // Then [you assert that it worked]
}

Теперь, когда этот тест пройден, вы можете считать, что ваша регистрация пользователя работает и не должна проверять ее снова. Незачем. Вот почему он называется «модульный тест», потому что вы тестируете «модули».

Теперь во втором тесте единица, которую вы тестируете, является частью «подтверждения»:

func testEmailConfirmation() {
  // Given [new email/username, you can call the registration method with this new email here]
  // When [you apply your confirmation flow]
  // Then [you assert that the confirmation is working]
}

Вы можете вызвать функцию регистрации пользователя (не тестовую, реальную функцию), настроенную для другого случайного электронного письма, и выполнить утверждения на основе этого электронного письма.

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...