Search code examples
swiftunit-testingxctestxctestcase

How can I run xctest for return ViewController func


How to write XCTestCase for below code

class HelpViewUseCase: HelpUseCaseProtocol, SubscriptionsHelpProtocol, ProfileHelpProtocol {
      func getHelpViewController() -> UIViewController {
        HelpViewController()
      }
    }

Another class which I'm unable to test

class UnifiedDirectAppointmentViewModel: UnifiedHistoryRowViewModel {       
      var rowType: UnifiedHistoryTableRowType {
        .directBooking
      }
        
          let appointmentResponse: DirectBookingInfoModel
        
      init?(forRowModel rowModel: UnifiedHistoryRowModel) {
        guard let data = rowModel.data.data as? DirectBookingInfoModel else {
          Log.error("Failed init for appointment \(rowModel)")
          return nil
        }
        appointmentResponse = data
      }
        }
        
extension UnifiedDirectAppointmentViewModel {
      var reuseIdentifier: String {
        DirectAppointmentTableViewCell.identifier
      }
      var bundle: Bundle? {
        Bundle(for: DirectAppointmentTableViewCell.self)
      }
    }

I'm new to unit test and was wondering how can I test aove classes. Thanks in advance for the suggestions and help


Solution

  • A unit test (or "microtest") should:

    • Set up something to call (Arrange)
    • Call the behavior we want to exercise (Act)
    • Confirm the expected result (Assert)

    This is a sequence often called the 3 A's, for Arrange, Act, Assert. I like to separate them with blank lines to make it clear what role each line of test code is playing.

    For your first example, you have getHelpViewController() which returns a UIViewController, specifically a HelpViewController. So we can test that as follows. (I don't normally use comments, but did so here to identify the purpose of each line for you.)

    // The class creates a test suite, a collection of tests.
    // Subclass XCTestCase.
    // Name it after the type you want to test, and add "Tests".
    // final is not required, but can give a minor speed improvement.
    final class HelpViewUseCaseTests: XCTestCase {
    
        // In XCTest, a test method must start with the letters "test".
        // Name it for the behavior you want to test.
        // In this case, the name of the method is good enough.
        // The underscore is not required. I just like the separation in the name.
        // I declare all my test methods as throwing because it
        // makes it easier to use throwing test helpers like XCTUnwrap.
        func test_getHelpViewController() throws {
            // Arrange
            let useCase = HelpViewUseCase()
    
            // Act
            let result = useCase.getHelpViewController()
    
            // Assert
            XCTAssertTrue(
                result is HelpViewController,
                "Expected a HelpViewController, but was a \(type(of: result))"
            )
        }
    }
    

    I added a message to the XCTAssertTrue because if it fails, I want to know more than "this wasn't true." I want to know why. So I have the message state the expectation, and the actual type. Try breaking the production code by returning the wrong type of view controller to see what the message looks like. (When writing a test, it's important to make it fail somehow to check that it's working, and if a failure gives enough information.)

    Your second example is really a separate question, and shouldn't be lumped in with the other question. Feel free to message me directly.

    I've written a book that should help you get started with unit testing in Swift. See my profile for details.