Level Up Coding

Coding tutorials and news. The developer homepage gitconnected.com && skilled.dev && levelup.dev

Follow publication

Find potential memory leaks with automated tests

Luis Piura
Level Up Coding
Published in
7 min readJan 20, 2021

--

Photo by Jorge Ramirez on Unsplash
var person = Person()
var person = Person()
weak var anotherPerson: Person? = person

Find retain cycles and memory leaks with testing

class UserProfileLoader {   private let client: HTTPClient
private let url: URL
init(url: URL, client: HTTPClient) {
self.url = url
self.client = client
}
enum Error: Swift.Error {
case invalidProfileData
case connectivity
}
enum Result: Equatable {
case success(UserProfile)
case failure(Error)
}
func loadProfile(completion: @escaping (Result) -> Void) {
client.get(from: url) { data in
let
result = self.map(data: data)
completion(result)
}
}
func map(data: HTTPClientResult) -> Result {
return .success(UserProfile(id: "an-user-id"))
}
}
enum HTTPClientResult {
case success(Data)
case failure(Error)
}
protocol HTTPClient { func get(from url: URL,
completion: @escaping (HTTPClientResult) -> Void)
}class HTTPClientSpy: HTTPClient { var completion: ((HTTPClientResult) -> Void)? = nil func get(from url: URL,
completion: @escaping (HTTPClientResult) -> Void) {

self.completion = completion
}
}
struct UserProfile: Equatable {
var id: String
}
func test_load_withSuccesfulClientResponseDeliversSuccesLoadingResult() {   let url = URL(string: "https://a-url.com")!
let client = HTTPClientSpy()
let
sut = UserProfileLoader(url: url, client: client)
}
func test_load_withSuccesfulClientResponseDeliversSuccesLoadingResult() {   let url = URL(string: "https://a-url.com")!
let client = HTTPClientSpy()
let
sut = UserProfileLoader(url: url, client: client)
var capturedResults = [UserProfileLoader.Result]()
sut.loadProfile { capturedResults.append($0) }
}
func test_load_withSuccesfulClientResponseDeliversSuccesLoadingResult() {   let url = URL(string: "https://a-url.com")!
let client = HTTPClientSpy()
let
sut = UserProfileLoader(url: url, client: client)
var capturedResults = [UserProfileLoader.Result]()
sut.loadProfile { capturedResults.append($0) }
client.completion?(.success(Data()))}
class MemoryLeaksTests: XCTestCase {   func test_load_withSuccesfulCallDeliversSuccesLoadingResult() {      let url = URL(string: "https://a-url.com")!
let client = HTTPClientSpy()
let
sut = UserProfileLoader(url: url, client: client)
let expectedResult: UserProfileLoader.Result =
.success(UserProfile(id: "an-user-id"))
var capturedResults = [UserProfileLoader.Result]()
sut.loadProfile { capturedResults.append($0) }
client.completion?(.success(Data()))
XCTAssertEqual(capturedResults, [expectedResult]) }}
class MemoryLeaksTests: XCTestCase {   func test_load_withSuccesfulCallDeliversSuccesLoadingResult() {      let url = URL(string: "https://a-url.com")!
let client = HTTPClientSpy()
let
sut = UserProfileLoader(url: url, client: client)
addTeardownBlock { [weak sut, weak client] in
XCTAssertNil(client, "Instance has not been deallocated")
XCTAssertNil(sut, "Instance has not been deallocated")
}
let expectedResult: UserProfileLoader.Result =
.success(UserProfile(id: "an-user-id"))
var capturedResults = [UserProfileLoader.Result]()
sut.loadProfile { capturedResults.append($0) }
client.completion?(.success(Data()))
XCTAssertEqual(capturedResults, [expectedResult]) }}
func loadProfile(completion: @escaping (Result) -> Void) {
client.get(from: url) { data in
completion(UserProfileLoader.map(data: data))
}
}
static func map(data: HTTPClientResult) -> Result {
return .success(UserProfile(id: "an-user-id"))
}
class MemoryLeaksTests: XCTestCase {   func test_load_withSuccesfulCallDeliversSuccesLoadingResult() {      let (sut, client) = 
makeSUT(url: URL(string: "https://a-url.com")!)
let expectedResult: UserProfileLoader.Result =
.success(UserProfile(id: "an-user-id"))
var capturedResults = [UserProfileLoader.Result]()
sut.loadProfile { capturedResults.append($0) }
client.completion?(.success(Data()))
XCTAssertEqual(capturedResults, [expectedResult])
}
// MARK: - Helpers func makeSUT(url: URL,
file: StaticString = #filePath,
line: UInt = #line) -> (sut: UserProfileLoader, client: HTTPClientSpy) {
let client = HTTPClientSpy()
let sut = UserProfileLoader(url: url, client: client)
addTeardownBlock { [weak sut, weak client] in
XCTAssertNil(client,
"Instance has not been deallocated",
file: file,
line: line)
XCTAssertNil(sut,
"Instance has not been deallocated",
file: file,
line: line)
}
return (sut, client) }}

--

--

No responses yet

Write a response