Skip to content

Commit

Permalink
Use test doubles AccountSettingsServiceTests (#20862)
Browse files Browse the repository at this point in the history
  • Loading branch information
mokagio authored Jul 7, 2023
2 parents 71ac312 + d244fdc commit 4477598
Show file tree
Hide file tree
Showing 9 changed files with 217 additions and 118 deletions.
40 changes: 26 additions & 14 deletions WordPress/WordPress.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -862,6 +862,9 @@
3F73BE5F24EB3B4400BE99FF /* WhatIsNewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F73BE5E24EB3B4400BE99FF /* WhatIsNewView.swift */; };
3F751D462491A93D0008A2B1 /* ZendeskUtilsTests+Plans.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F751D452491A93D0008A2B1 /* ZendeskUtilsTests+Plans.swift */; };
3F758FD524F6FB4900BBA2FC /* AnnouncementsStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F758FD424F6FB4900BBA2FC /* AnnouncementsStore.swift */; };
3F759FBA2A2DA93B0039A845 /* WPAccount+Fixture.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F759FB92A2DA93B0039A845 /* WPAccount+Fixture.swift */; };
3F759FBC2A2DB2CF0039A845 /* TestError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F759FBB2A2DB2CF0039A845 /* TestError.swift */; };
3F759FBE2A2DB3280039A845 /* AccountSettingsRemoteInterfaceStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F759FBD2A2DB3280039A845 /* AccountSettingsRemoteInterfaceStub.swift */; };
3F762E9326784A950088CD45 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F762E9226784A950088CD45 /* Logger.swift */; };
3F762E9526784B540088CD45 /* WireMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F762E9426784B540088CD45 /* WireMock.swift */; };
3F762E9726784BED0088CD45 /* FancyAlertComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F762E9626784BED0088CD45 /* FancyAlertComponent.swift */; };
Expand Down Expand Up @@ -6560,6 +6563,9 @@
3F73BE5E24EB3B4400BE99FF /* WhatIsNewView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WhatIsNewView.swift; sourceTree = "<group>"; };
3F751D452491A93D0008A2B1 /* ZendeskUtilsTests+Plans.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ZendeskUtilsTests+Plans.swift"; sourceTree = "<group>"; };
3F758FD424F6FB4900BBA2FC /* AnnouncementsStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnnouncementsStore.swift; sourceTree = "<group>"; };
3F759FB92A2DA93B0039A845 /* WPAccount+Fixture.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WPAccount+Fixture.swift"; sourceTree = "<group>"; };
3F759FBB2A2DB2CF0039A845 /* TestError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestError.swift; sourceTree = "<group>"; };
3F759FBD2A2DB3280039A845 /* AccountSettingsRemoteInterfaceStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountSettingsRemoteInterfaceStub.swift; sourceTree = "<group>"; };
3F762E9226784A950088CD45 /* Logger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = "<group>"; };
3F762E9426784B540088CD45 /* WireMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WireMock.swift; sourceTree = "<group>"; };
3F762E9626784BED0088CD45 /* FancyAlertComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FancyAlertComponent.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -12210,13 +12216,14 @@
59B48B601B99E0B0008EBB84 /* TestUtilities */ = {
isa = PBXGroup;
children = (
59B48B611B99E132008EBB84 /* JSONObject.swift */,
E157D5DF1C690A6C00F04FB9 /* ImmuTableTestUtils.swift */,
570BFD8F2282418A007859A8 /* PostBuilder.swift */,
2481B1D4260D4E8B00AE59DB /* AccountBuilder.swift */,
57B71D4D230DB5F200789A68 /* BlogBuilder.swift */,
E157D5DF1C690A6C00F04FB9 /* ImmuTableTestUtils.swift */,
59B48B611B99E132008EBB84 /* JSONObject.swift */,
F11023A223186BCA00C4E84A /* MediaBuilder.swift */,
57889AB723589DF100DAE56D /* PageBuilder.swift */,
2481B1D4260D4E8B00AE59DB /* AccountBuilder.swift */,
570BFD8F2282418A007859A8 /* PostBuilder.swift */,
3F759FBB2A2DB2CF0039A845 /* TestError.swift */,
);
name = TestUtilities;
sourceTree = "<group>";
Expand Down Expand Up @@ -12374,26 +12381,27 @@
5D7A577D1AFBFD7C0097C028 /* Models */ = {
isa = PBXGroup;
children = (
F1B1E7A224098FA100549E2A /* BlogTests.swift */,
E6A2158F1D1065F200DE5270 /* AbstractPostTest.swift */,
8B8C814C2318073300A0E620 /* BasePostTests.swift */,
246D0A0225E97D5D0028B83F /* Blog+ObjcTests.m */,
FEE48EFE2A4C9855008A48E0 /* Blog+PublicizeTests.swift */,
4AD5657128E543A30054C676 /* BlogQueryTests.swift */,
B55F1AA11C107CE200FD04D4 /* BlogSettingsDiscussionTests.swift */,
F1B1E7A224098FA100549E2A /* BlogTests.swift */,
24A2948225D602710000A51E /* BlogTimeZoneTests.m */,
D848CC1620FF38EA00A9038F /* FormattableCommentRangeTests.swift */,
0879FC151E9301DD00E1EFC8 /* MediaTests.swift */,
C38C5D8027F61D2C002F517E /* MenuItemTests.swift */,
D848CC1420FF33FC00A9038F /* NotificationContentRangeTests.swift */,
D826D67E211D21C700A5D8FE /* NullMockUserDefaults.swift */,
5960967E1CF7959300848496 /* PostTests.swift */,
8BBBEBB124B8F8C0005E358E /* ReaderCardTests.swift */,
E6B9B8A91B94E1FE0001B92F /* ReaderPostTest.m */,
B55F1AA11C107CE200FD04D4 /* BlogSettingsDiscussionTests.swift */,
E6A2158F1D1065F200DE5270 /* AbstractPostTest.swift */,
5960967E1CF7959300848496 /* PostTests.swift */,
0879FC151E9301DD00E1EFC8 /* MediaTests.swift */,
D826D67E211D21C700A5D8FE /* NullMockUserDefaults.swift */,
8B8C814C2318073300A0E620 /* BasePostTests.swift */,
24A2948225D602710000A51E /* BlogTimeZoneTests.m */,
24C69A8A2612421900312D9A /* UserSettingsTests.swift */,
24C69AC12612467C00312D9A /* UserSettingsTestsObjc.m */,
3F759FB92A2DA93B0039A845 /* WPAccount+Fixture.swift */,
2481B1E7260D4EAC00AE59DB /* WPAccount+LookupTests.swift */,
2481B20B260D8FED00AE59DB /* WPAccount+ObjCLookupTests.m */,
C38C5D8027F61D2C002F517E /* MenuItemTests.swift */,
FEE48EFE2A4C9855008A48E0 /* Blog+PublicizeTests.swift */,
);
name = Models;
sourceTree = "<group>";
Expand Down Expand Up @@ -15381,6 +15389,7 @@
children = (
9363113E19FA996700B0C739 /* AccountServiceTests.swift */,
4A9948E129714EF1006282A9 /* AccountSettingsServiceTests.swift */,
3F759FBD2A2DB3280039A845 /* AccountSettingsRemoteInterfaceStub.swift */,
F1F083F5241FFE930056D3B1 /* AtomicAuthenticationServiceTests.swift */,
46F58500262605930010A723 /* BlockEditorSettingsServiceTests.swift */,
FEA312832987FB0100FFD405 /* BlogJetpackTests.swift */,
Expand Down Expand Up @@ -23513,6 +23522,7 @@
7E987F58210811CC00CAFB88 /* NotificationContentRouterTests.swift in Sources */,
E1C9AA561C10427100732665 /* MathTest.swift in Sources */,
93A379EC19FFBF7900415023 /* KeychainTest.m in Sources */,
3F759FBE2A2DB3280039A845 /* AccountSettingsRemoteInterfaceStub.swift in Sources */,
F1BB660C274E704D00A319BE /* LikeUserHelperTests.swift in Sources */,
436D5655212209D600CEAA33 /* RegisterDomainDetailsServiceProxyMock.swift in Sources */,
F1450CF92437EEBB00A28BFE /* MediaRequestAuthenticatorTests.swift in Sources */,
Expand All @@ -23525,6 +23535,7 @@
FF9A6E7121F9361700D36D14 /* MediaUploadHashTests.swift in Sources */,
B532ACCF1DC3AB8E00FFFA57 /* NotificationSyncMediatorTests.swift in Sources */,
7E4A772F20F7FDF8001C706D /* ActivityLogTestData.swift in Sources */,
3F759FBC2A2DB2CF0039A845 /* TestError.swift in Sources */,
40E7FEC82211EEC00032834E /* LastPostStatsRecordValueTests.swift in Sources */,
57240224234E5BE200227067 /* PostServiceSelfHostedTests.swift in Sources */,
B59D40A61DB522DF003D2D79 /* NSAttributedStringTests.swift in Sources */,
Expand Down Expand Up @@ -23630,6 +23641,7 @@
F17A2A2023BFBD84001E96AC /* UIView+ExistingConstraints.swift in Sources */,
9A9D34FD23607CCC00BC95A3 /* AsyncOperationTests.swift in Sources */,
B5552D821CD1061F00B26DF6 /* StringExtensionsTests.swift in Sources */,
3F759FBA2A2DA93B0039A845 /* WPAccount+Fixture.swift in Sources */,
8B821F3C240020E2006B697E /* PostServiceUploadingListTests.swift in Sources */,
73178C3521BEE9AC00E37C9A /* TitleSubtitleHeaderTests.swift in Sources */,
08AAD6A11CBEA610002B2418 /* MenusServiceTests.m in Sources */,
Expand Down
33 changes: 5 additions & 28 deletions WordPress/WordPressTest/AccountServiceTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -147,24 +147,10 @@ class AccountServiceTests: CoreDataTestCase {

func testMergeMultipleDuplicateAccounts() throws {
let context = contextManager.mainContext
let account1 = WPAccount(context: context)
account1.userID = 1
account1.username = "username"
account1.authToken = "authToken"
account1.uuid = UUID().uuidString

let account2 = WPAccount(context: context)
account2.userID = 1
account2.username = "username"
account2.authToken = "authToken"
account2.uuid = UUID().uuidString

let account3 = WPAccount(context: context)
account3.userID = 1
account3.username = "username"
account3.authToken = "authToken"
account3.uuid = UUID().uuidString

let account1 = WPAccount.fixture(context: context, userID: 1)
let account2 = WPAccount.fixture(context: context, userID: 1)
let account3 = WPAccount.fixture(context: context, userID: 1)

account1.addBlogs(createMockBlogs(withIDs: [1, 2, 3, 4, 5, 6], in: context))
account2.addBlogs(createMockBlogs(withIDs: [1, 2, 3], in: context))
Expand Down Expand Up @@ -240,17 +226,8 @@ class AccountServiceTests: CoreDataTestCase {
}

func testPurgeAccount() throws {
let account1 = WPAccount(context: mainContext)
account1.userID = 1
account1.username = "username"
account1.authToken = "authToken"
account1.uuid = UUID().uuidString

let account2 = WPAccount(context: mainContext)
account2.userID = 1
account2.username = "username"
account2.authToken = "authToken"
account2.uuid = UUID().uuidString
let account1 = WPAccount.fixture(context: mainContext, userID: 1)
let account2 = WPAccount.fixture(context: mainContext, userID: 2)

contextManager.saveContextAndWait(mainContext)
try XCTAssertEqual(mainContext.count(for: WPAccount.fetchRequest()), 2)
Expand Down
77 changes: 77 additions & 0 deletions WordPress/WordPressTest/AccountSettingsRemoteInterfaceStub.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
@testable import WordPress
import WordPressKit

class AccountSettingsRemoteInterfaceStub: AccountSettingsRemoteInterface {

let updateSettingResult: Result<(), Error>
let getSettingsResult: Result<AccountSettings, Error>
let changeUsernameShouldSucceed: Bool
let suggestUsernamesResult: [String]
let updatePasswordResult: Result<(), Error>
let closeAccountResult: Result<(), Error>

init(
updateSettingResult: Result<Void, Error> = .success(()),
// Defaulting to failure to avoid having to create AccountSettings here, because it required an NSManagedContext
getSettingsResult: Result<AccountSettings, Error> = .failure(TestError()),
changeUsernameShouldSucceed: Bool = true,
suggestUsernamesResult: [String] = [],
updatePasswordResult: Result<Void, Error> = .success(()),
closeAccountResult: Result<Void, Error> = .success(())
) {
self.updateSettingResult = updateSettingResult
self.getSettingsResult = getSettingsResult
self.changeUsernameShouldSucceed = changeUsernameShouldSucceed
self.suggestUsernamesResult = suggestUsernamesResult
self.updatePasswordResult = updatePasswordResult
self.closeAccountResult = closeAccountResult
}

func updateSetting(_ change: AccountSettingsChange, success: @escaping () -> Void, failure: @escaping (Error) -> Void) {
switch updateSettingResult {
case .success:
success()
case .failure(let error):
failure(error)
}
}

func getSettings(success: @escaping (WordPressKit.AccountSettings) -> Void, failure: @escaping (Error) -> Void) {
switch getSettingsResult {
case .success(let settings):
success(settings)
case .failure(let error):
failure(error)
}
}

func changeUsername(to username: String, success: @escaping () -> Void, failure: @escaping () -> Void) {
if changeUsernameShouldSucceed {
success()
} else {
failure()
}
}

func suggestUsernames(base: String, finished: @escaping ([String]) -> Void) {
finished(suggestUsernamesResult)
}

func updatePassword(_ password: String, success: @escaping () -> Void, failure: @escaping (Error) -> Void) {
switch updatePasswordResult {
case .success:
success()
case .failure(let error):
failure(error)
}
}

func closeAccount(success: @escaping () -> Void, failure: @escaping (Error) -> Void) {
switch closeAccountResult {
case .success:
success()
case .failure(let error):
failure(error)
}
}
}
105 changes: 67 additions & 38 deletions WordPress/WordPressTest/AccountSettingsServiceTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,10 @@ class AccountSettingsServiceTests: CoreDataTestCase {
private var service: AccountSettingsService!

override func setUp() {
let account = WPAccount(context: mainContext)
account.username = "test"
account.authToken = "token"
account.userID = 1
account.uuid = UUID().uuidString

let settings = ManagedAccountSettings(context: mainContext)
settings.account = account
settings.username = "Username"
settings.displayName = "Display Name"
settings.primarySiteID = 1
settings.aboutMe = "<empty>"
settings.email = "[email protected]"
settings.firstName = "Test"
settings.lastName = "User"
settings.language = "en"
settings.webAddress = "https://test.wordpress.com"

let account = WPAccount.fixture(context: mainContext)
_ = makeManagedAccountSettings(context: mainContext, account: account)
contextManager.saveContextAndWait(mainContext)
service = makeService(contextManager: contextManager, account: account)

service = AccountSettingsService(
userID: account.userID.intValue,
Expand All @@ -35,41 +20,44 @@ class AccountSettingsServiceTests: CoreDataTestCase {
)
}

private func managedAccountSettings() -> ManagedAccountSettings? {
contextManager.performQuery { context in
let request = NSFetchRequest<NSFetchRequestResult>(entityName: ManagedAccountSettings.entityName())
request.predicate = NSPredicate(format: "account.userID = %d", self.service.userID)
request.fetchLimit = 1
guard let results = (try? context.fetch(request)) as? [ManagedAccountSettings] else {
return nil
}
return results.first
}
}

func testUpdateSuccess() throws {
stub(condition: isPath("/rest/v1.1/me/settings")) { _ in
HTTPStubsResponse(jsonObject: [String: Any](), statusCode: 200, headers: nil)
}
// We've seen some flakiness in CI on this test, and therefore are using a stub object rather than stubbing the HTTP requests.
// Since this approach bypasses the entire network stack, the hope is that it'll result in a more robust test.
//
// This is the second test in this class edited this way.
// If we'll need to update a third, we shall also take the time to update the rest of the tests.
let service = AccountSettingsService(
userID: 1,
remote: AccountSettingsRemoteInterfaceStub(updateSettingResult: .success(())),
coreDataStack: contextManager
)

waitUntil { done in
self.service.saveChange(.firstName("Updated"), finished: { success in
service.saveChange(.firstName("Updated"), finished: { success in
expect(success).to(beTrue())
done()
})
}

expect(self.managedAccountSettings()?.firstName).to(equal("Updated"))
}

func testUpdateFailure() throws {
stub(condition: isPath("/rest/v1.1/me/settings")) { _ in
HTTPStubsResponse(jsonObject: [String: Any](), statusCode: 500, headers: nil)
}
// We've seen some flakiness in CI on this test, and therefore are using a stub object rather than stubbing the HTTP requests.
// Since this approach bypasses the entire network stack, the hope is that it'll result in a more robust test.
let service = AccountSettingsService(
userID: 1,
remote: AccountSettingsRemoteInterfaceStub(updateSettingResult: .failure(TestError())),
coreDataStack: contextManager
)

waitUntil { done in
self.service.saveChange(.firstName("Updated"), finished: { success in
service.saveChange(.firstName("Updated"), finished: { success in
expect(success).to(beFalse())
done()
})
}

expect(self.managedAccountSettings()?.firstName).to(equal("Test"))
}

Expand Down Expand Up @@ -100,3 +88,44 @@ class AccountSettingsServiceTests: CoreDataTestCase {
wait(for: [notCrash], timeout: 0.5)
}
}

extension AccountSettingsServiceTests {

private func makeManagedAccountSettings(
context: NSManagedObjectContext,
account: WPAccount
) -> ManagedAccountSettings {
let settings = ManagedAccountSettings(context: context)
settings.account = account
settings.username = "Username"
settings.displayName = "Display Name"
settings.primarySiteID = 1
settings.aboutMe = "<empty>"
settings.email = "[email protected]"
settings.firstName = "Test"
settings.lastName = "User"
settings.language = "en"
settings.webAddress = "https://test.wordpress.com"
return settings
}

private func makeService(contextManager: ContextManager, account: WPAccount) -> AccountSettingsService {
AccountSettingsService(
userID: account.userID.intValue,
remote: AccountSettingsRemote(wordPressComRestApi: account.wordPressComRestApi),
coreDataStack: contextManager
)
}

private func managedAccountSettings() -> ManagedAccountSettings? {
contextManager.performQuery { context in
let request = NSFetchRequest<NSFetchRequestResult>(entityName: ManagedAccountSettings.entityName())
request.predicate = NSPredicate(format: "account.userID = %d", self.service.userID)
request.fetchLimit = 1
guard let results = (try? context.fetch(request)) as? [ManagedAccountSettings] else {
return nil
}
return results.first
}
}
}
4 changes: 1 addition & 3 deletions WordPress/WordPressTest/BlogTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -199,9 +199,7 @@ final class BlogTests: CoreDataTestCase {
// Create an account with duplicated blogs
let xmlrpc = "https://xmlrpc.test.wordpress.com"
let account = try await contextManager.performAndSave { context in
let account = WPAccount(context: context)
account.username = "username"
account.authToken = "authToken"
let account = WPAccount.fixture(context: context)
account.blogs = Set(
(1...10).map { _ in
let blog = BlogBuilder(context).build()
Expand Down
Loading

0 comments on commit 4477598

Please sign in to comment.