如何在XCode中将字符串从一个单元测试传递到另一个?

时间:2018-09-04 22:54:55

标签: ios objective-c xcode unit-testing

我有两个单元测试,testUserRegistration和testEmailConfirmation。注册测试首先运行,我创建了一个唯一的电子邮件来注册一个随机整数,例如autoTest1234@test.com或autoTest4928@test.com。在下一个测试testEmailConfirmation中,我需要使用在上一个测试中创建的用户名。如何将其从一种测试方法发送到另一种方法?

4 个答案:

答案 0 :(得分:2)

这不是您应该如何考虑单元测试的方法。

首先,您不应该对测试顺序进行评估:您的测试可能会以随机顺序运行,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]
}

您可以调用配置有另一封随机电子邮件的用户注册功能(而不是测试,真实功能),并根据该电子邮件进行断言。

希望有帮助!

答案 1 :(得分:0)

您可以通过将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类,并在 Swift 中调用super.setUp()super.tearDown(),如果是,则调用[super setUp][super tearDown] Objective-C

我已经将这种结构用于集成测试两年多了,该测试需要网络和身份验证才能取得成功。

答案 2 :(得分:0)

似乎您不是在进行单元测试,而是在进行集成测试或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具有自己的逻辑,因此不能保证注册测试会在注册之前进行。目前,它按字母顺序进行测试,但是可能会有所变化,而并行化则可能使您头痛。

答案 3 :(得分:-1)

您可以尝试使用segue:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        let destinationVC: nameofdestinationVC = segue.destination as! nameofdestinationVC
        destinationVC.string = string var in other VC!
        
    }

相关问题