             }
             
             func makeExpectedTabViewControllerRoots() -> [UIViewController] {
-                return [newsModuleFactory.stubInterface, knowledgeListModuleProviding.stubInterface]
+                return [newsModule.stubInterface, knowledgeListModule.stubInterface]
             }
             
             func rootNavigationTabControllers() -> [UINavigationController] {
-                return tabModuleFactory.capturedTabModules.flatMap({ $0 as? UINavigationController })
+                return tabModule.capturedTabModules.flatMap({ $0 as? UINavigationController })
+            }
+            
+            func navigationController(for viewController: UIViewController) -> CapturingNavigationController? {
+                return tabModule.navigationController(for: viewController)
             }
             
         }
         
         private let director: ApplicationDirector
-        private let rootModuleFactory: StubRootModuleFactory
-        private let tutorialModuleFactory: StubTutorialModuleFactory
-        private let preloadModuleFactory: StubPreloadModuleFactory
-        private let tabModuleFactory: StubTabModuleFactory
-        private let newsModuleFactory: StubNewsModuleFactory
-        private let messagesModuleFactory: StubMessagesModuleFactory
-        private let loginModuleFactory: StubLoginModuleFactory
+        private let rootModule: StubRootModuleFactory
+        private let tutorialModule: StubTutorialModuleFactory
+        private let preloadModule: StubPreloadModuleFactory
+        private let tabModule: StubTabModuleFactory
+        private let newsModule: StubNewsModuleFactory
+        private let messagesModule: StubMessagesModuleFactory
+        private let loginModule: StubLoginModuleFactory
         private let windowWireframe: CapturingWindowWireframe
-        private let messageDetailModuleFactory: StubMessageDetailModuleProviding
-        private let knowledgeListModuleProviding: StubKnowledgeListModuleProviding
-        private let knowledgeDetailModuleProviding: StubKnowledgeDetailModuleProviding
+        private let messageDetailModule: StubMessageDetailModuleProviding
+        private let knowledgeListModule: StubKnowledgeListModuleProviding
+        private let knowledgeDetailModule: StubKnowledgeDetailModuleProviding
         private let linkRouter: StubLinkRouter
         private let webModuleProviding: StubWebMobuleProviding
         private let urlOpener: CapturingURLOpener
         
         init() {
-            rootModuleFactory = StubRootModuleFactory()
-            tutorialModuleFactory = StubTutorialModuleFactory()
-            preloadModuleFactory = StubPreloadModuleFactory()
+            rootModule = StubRootModuleFactory()
+            tutorialModule = StubTutorialModuleFactory()
+            preloadModule = StubPreloadModuleFactory()
             windowWireframe = CapturingWindowWireframe()
-            tabModuleFactory = StubTabModuleFactory()
-            newsModuleFactory = StubNewsModuleFactory()
-            messagesModuleFactory = StubMessagesModuleFactory()
-            loginModuleFactory = StubLoginModuleFactory()
-            messageDetailModuleFactory = StubMessageDetailModuleProviding()
-            knowledgeListModuleProviding = StubKnowledgeListModuleProviding()
-            knowledgeDetailModuleProviding = StubKnowledgeDetailModuleProviding()
+            tabModule = StubTabModuleFactory()
+            newsModule = StubNewsModuleFactory()
+            messagesModule = StubMessagesModuleFactory()
+            loginModule = StubLoginModuleFactory()
+            messageDetailModule = StubMessageDetailModuleProviding()
+            knowledgeListModule = StubKnowledgeListModuleProviding()
+            knowledgeDetailModule = StubKnowledgeDetailModuleProviding()
             linkRouter = StubLinkRouter()
             webModuleProviding = StubWebMobuleProviding()
             urlOpener = CapturingURLOpener()

            builder.withAnimations(false)
            builder.with(windowWireframe)
            builder.with(StubNavigationControllerFactory())
            builder.with(rootModuleFactory)
            builder.with(tutorialModuleFactory)
            builder.with(preloadModuleFactory)
            builder.with(tabModuleFactory)
            builder.with(newsModuleFactory)
            builder.with(messagesModuleFactory)
            builder.with(loginModuleFactory)
            builder.with(messageDetailModuleFactory)
            builder.with(knowledgeListModuleProviding)
            builder.with(knowledgeDetailModuleProviding)
            builder.with(linkRouter)
            builder.with(webModuleProviding)
            builder.with(urlOpener)

    
    func testWhenTheNewsModuleRequestsLoginTheMessagesControllerIsPushedOntoItsNavigationController() {
        context.navigateToTabController()
        let newsNavigationController = context.navigationController(for: context.newsModule.stubInterface)
        context.newsModule.simulateLoginRequested()
        
        XCTAssertEqual(context.messages.stubInterface, newsNavigationController?.pushedViewControllers.last)
    }
    
    func testWhenTheNewsModuleRequestsShowingPrivateMessagesTheMessagesControllerIsPushedOntoItsNavigationController() {
        context.navigateToTabController()
        let newsNavigationController = context.navigationController(for: context.newsModule.stubInterface)
        context.newsModule.simulatePrivateMessagesDisplayRequested()
        
        XCTAssertEqual(context.messages.stubInterface, newsNavigationController?.pushedViewControllers.last)
    }
    
    func testWhenTheMessagesModuleRequestsDismissalItIsDismissedFromTheTabController() {
        context.navigateToTabController()
        context.newsModule.simulatePrivateMessagesDisplayRequested()
        context.messages.simulateDismissalRequested()
        
        XCTAssertTrue(context.tabModule.stubInterface.didDismissViewController)
    }
    
    func testWhenTheMessagesModuleRequestsDismissalTheNewsNavigationControllersPopsToTheNewsModule() {
        context.navigateToTabController()
        let newsNavigationController = context.navigationController(for: context.newsModule.stubInterface)
        context.newsModule.simulatePrivateMessagesDisplayRequested()
        context.messages.simulateDismissalRequested()
        
        XCTAssertEqual(context.newsModule.stubInterface, newsNavigationController?.viewControllerPoppedTo)
    }
    
    func testWhenTheMessagesModuleRequestsResolutionForUserTheLoginModuleIsPresentedOnTopOfTheTabController() {
        context.navigateToTabController()
        context.newsModule.simulatePrivateMessagesDisplayRequested()
        context.messages.simulateResolutionForUser( { _ in })
        let navController = context.tabModule.stubInterface.capturedPresentedViewController as? UINavigationController
        
        XCTAssertEqual(navController?.topViewController, context.loginModule.stubInterface)
    }
    
    func testWhenTheMessagesModuleRequestsResolutionForUserTheLoginModuleIsPresentedUsingTheFormSheetModalPresentationStyle() {
        context.navigateToTabController()
        context.newsModule.simulatePrivateMessagesDisplayRequested()
        context.messages.simulateResolutionForUser({ _ in })
        
        XCTAssertEqual(context.loginModule.stubInterface.modalPresentationStyle, .formSheet)
    }
    
    func testWhenShowingLoginForMessagesControllerWhenModuleCancelsLoginTheMessagesModuleIsToldResolutionFailed() {
        context.navigateToTabController()
        context.newsModule.simulatePrivateMessagesDisplayRequested()
        var userResolved = true
        context.messages.simulateResolutionForUser({ userResolved = $0 })
        context.loginModule.simulateLoginCancelled()
        
        XCTAssertFalse(userResolved)
    }
    
    func testWhenShowingLoginForMessagesControllerTheMessagesModuleIsNotToldResolutionFailedBeforeLoginIsCancelled() {
        context.navigateToTabController()
        context.newsModule.simulatePrivateMessagesDisplayRequested()
        var userResolved = true
        context.messages.simulateResolutionForUser({ userResolved = $0 })
        
        XCTAssertTrue(userResolved)
    }
    
    func testWhenShowingLoginForMessagesControllerWhenModuleLogsInTheMessagesModuleIsToldResolutionSucceeded() {
        context.navigateToTabController()
        context.newsModule.simulatePrivateMessagesDisplayRequested()
        var userResolved = false
        context.messages.simulateResolutionForUser({ userResolved = $0 })
        context.loginModule.simulateLoginSucceeded()
        
        XCTAssertTrue(userResolved)
    }
    
    func testWhenShowingLoginForMessagesControllerTheMessagesModuleIsNotToldResolutionSucceededBeforeUserLogsIn() {
        context.navigateToTabController()
        context.newsModule.simulatePrivateMessagesDisplayRequested()
        var userResolved = false
        context.messages.simulateResolutionForUser({ userResolved = $0 })
        
        XCTAssertFalse(userResolved)
    }
    
    func testWhenShowingLoginForMessagesControllerWhenLoginSucceedsItIsDismissed() {
        context.navigateToTabController()
        context.newsModule.simulatePrivateMessagesDisplayRequested()
        context.messages.simulateResolutionForUser { (_) in }
        context.loginModule.simulateLoginSucceeded()
        
        XCTAssertTrue(context.tabModule.stubInterface.didDismissViewController)
    }
    
    func testWhenMessagesModuleRequestsPresentationForMessageTheMessageDetailModuleIsBuiltUsingChosenMessage() {
        context.navigateToTabController()
        context.newsModule.simulatePrivateMessagesDisplayRequested()
        let message = AppDataBuilder.makeMessage()
        context.messages.simulateMessagePresentationRequested(message)
        
        XCTAssertEqual(message, context.messageDetailModule.capturedMessage)
    }
    
    func testWhenMessagesModuleRequestsPresentationForMessageTheMessageDetailModuleInterfaceIsPushedOntoMessagesNavigationController() {
        context.navigateToTabController()
        context.newsModule.simulatePrivateMessagesDisplayRequested()
        context.messages.simulateMessagePresentationRequested(AppDataBuilder.makeMessage())
        let navigationController = context.messages.stubInterface.navigationController
        
        XCTAssertEqual(context.messageDetailModule.stubInterface, navigationController?.topViewController)
    }
    
    func testWhenSelectingKnowledgeEntryTheKnowledgeEntryModuleIsPresented() {
        context.navigateToTabController()
        let knowledgeNavigationController = context.navigationController(for: context.knowledgeListModule.stubInterface)
        let entry = KnowledgeEntry2.random
        context.knowledgeListModule.simulateKnowledgeEntrySelected(entry)
        
        XCTAssertEqual(context.knowledgeDetailModule.stubInterface, knowledgeNavigationController?.topViewController)
        XCTAssertEqual(entry, context.knowledgeDetailModule.capturedModel)
    }
    
    func testWhenKnowledgeEntrySelectsWebLinkTheWebModuleIsPresentedOntoTheTabInterface() {
        context.navigateToTabController()
        let entry = KnowledgeEntry2.random
        context.knowledgeListModule.simulateKnowledgeEntrySelected(entry)
        let link = entry.links.randomElement().element
        let url = URL.random
        context.linkRouter.stubbedLinkActions[link] = .web(url)
        context.knowledgeDetailModule.simulateLinkSelected(link)
        let webModuleForURL = context.webModuleProviding.producedWebModules[url]
        
        XCTAssertNotNil(webModuleForURL)
        XCTAssertEqual(webModuleForURL, context.tabModule.stubInterface.capturedPresentedViewController)
    }
    
    func testWhenKnowledgeEntrySelectsExternalAppLinkTheURLLauncherIsToldToHandleTheURL() {
        context.navigateToTabController()
        let entry = KnowledgeEntry2.random
        context.knowledgeListModule.simulateKnowledgeEntrySelected(entry)
        let link = entry.links.randomElement().element
        let url = URL.random
        context.linkRouter.stubbedLinkActions[link] = .externalURL(url)
        context.knowledgeDetailModule.simulateLinkSelected(link)
        
        XCTAssertEqual(url, context.urlOpener.capturedURLToOpen)
    }
