SlideShare a Scribd company logo
Unit Testing
Zašto?
Kako ubiti

2 aplikacije
Jednim commitom.
Manje bugova.
Swift 

migracija?
Nema problema.
Manje stresa.
Kad se isplati?
Testiranje je
investicija
Što testirati?
Koliko se koristi?

Koliko je kompleksno?

Koliko je važna korektnost?
Što testirati?
1. Core logika

2. Prezentacija (ViewModel)
3. UI
Zašto ljudi ne

testiraju?
Testovi su

teški.
Ako je dizajn loš.
Teško za
testirati:
Dependency (UIKit,
Foundation, libovi)
Lagano za

testirati:
“Čisti” Swift
Business logika
Granice
Razdvojiti Swift od plaforme i
libraryja
Izdvojiti logiku aplikacije
MVVM
UIViewController
NAVIGACIJA
UIKIT
PRIKAZ
UI LOGIKA
NETWORKING
BUSINESS

LOGIKA
TRANSFORMA
CIJA
PODATAKA
MIJENJANJE

STANJA
UIViewController
NAVIGACIJA
UIKIT
PRIKAZ
UI LOGIKA
NETWORKINGBUSINESS

LOGIKA
TRANSFORMA
CIJA
PODATAKA
MIJENJANJE

STANJA
ViewModel
MVVM++
Example
States
LoadedLoading No data Error
States
class FeedViewModel {
enum ViewState {
case loading
case noData
case error(String)
case loaded([FeedCellModel])
}
}
Data
struct FeedCellModel {
let name: String
let description: String
let image: URL?
}
Lagano za verificirati,
bez stanja (nepromjenljivo)
class FeedViewModel {
func loadData() {
self.state = .loading
feedService.getFeedItem(page: 0) { result in
switch result {
case let .success(items):
if items.isEmpty {
self.state = .noData
} else {
let models = self.feedCellModels(from: items)
self.state = .loaded(models)
}
case let .failure(error):
let errorText = self.errorText(for: error)
self.state = .error(errorText)
}
}
}
}
class FeedViewModel {
func loadData() {
self.state = .loading
feedService.getFeedItem(page: 0) { result in
switch result {
case let .success(items):
if items.isEmpty {
self.state = .noData
} else {
let models = self.feedCellModels(from: items)
self.state = .loaded(models)
}
case let .failure(error):
let errorText = self.errorText(for: error)
self.state = .error(errorText)
}
}
}
}
class FeedViewModel {
func loadData() {
self.state = .loading
feedService.getFeedItem(page: 0) { result in
switch result {
case let .success(items):
if items.isEmpty {
self.state = .noData
} else {
let models = self.feedCellModels(from: items)
self.state = .loaded(models)
}
case let .failure(error):
let errorText = self.errorText(for: error)
self.state = .error(errorText)
}
}
}
}
class FeedViewModel {
func loadData() {
self.state = .loading
feedService.getFeedItem(page: 0) { result in
switch result {
case let .success(items):
if items.isEmpty {
self.state = .noData
} else {
let models = self.feedCellModels(from: items)
self.state = .loaded(models)
}
case let .failure(error):
let errorText = self.errorText(for: error)
self.state = .error(errorText)
}
}
}
}
class FeedViewModel {
func loadData() {
self.state = .loading
feedService.getFeedItem(page: 0) { result in
switch result {
case let .success(items):
if items.isEmpty {
self.state = .noData
} else {
let models = self.feedCellModels(from: items)
self.state = .loaded(models)
}
case let .failure(error):
let errorText = self.errorText(for: error)
self.state = .error(errorText)
}
}
}
}
class FeedViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
viewModel.onStateChanged = { [weak self] state in
guard let `self` = self else { return }
switch state {
case .noData:
self.refreshControl.endRefreshing()
self.manager.data = []
self.errorImage.isHidden = true
self.errorLabel.text = Localizable.error_empty_feed
self.errorView.isHidden = false
case .error(let error):
self.manager.data = []
self.refreshControl.endRefreshing()
self.errorImage.isHidden = false
self.errorLabel.text = error
self.errorView.isHidden = false
case .loaded(let items):
self.refreshControl.endRefreshing()
self.manager.data = items
self.errorView.isHidden = true
case .loading:
self.refreshControl.beginRefreshing()
}
}
}
Prednosti
1. Cijeli state na jednom mjestu
2. Manipulacija statea izdvojena iz iOS-a
3. Lagano ubacivanje dodatnog 

statea
Prednosti
Testabilan dizajn = dobar dizajn
Testiranje
1. Spremi promjenu statea u array.
2. Okini akcije.

3. Provjeri state array.
class FeedDetailsViewModelTests: XCTestCase {
var feedService: FeedServiceMock!
var states: [FeedDetailsViewModel.ViewState] = []
var viewModel: FeedDetailsViewModel!
override func setUp() {
super.setUp()
feedService = FeedServiceMock()
states = []
viewModel = FeedViewModel(feedService)
viewModel.onState = { self.states.append($0) }
}
class FeedDetailsViewModelTests: XCTestCase {
var feedService: FeedServiceMock!
var states: [FeedDetailsViewModel.ViewState] = []
var viewModel: FeedDetailsViewModel!
override func setUp() {
super.setUp()
feedService = FeedServiceMock()
states = []
viewModel = FeedViewModel(feedService)
viewModel.onState = { self.states.append($0) }
}
class FeedDetailsViewModelTests: XCTestCase {
var feedService: FeedServiceMock!
var states: [FeedDetailsViewModel.ViewState] = []
var viewModel: FeedDetailsViewModel!
override func setUp() {
super.setUp()
feedService = FeedServiceMock()
states = []
viewModel = FeedViewModel(feedService)
viewModel.onState = { self.states.append($0) }
}
class FeedDetailsViewModelTests: XCTestCase {
var feedService: FeedServiceMock!
var states: [FeedDetailsViewModel.ViewState] = []
var viewModel: FeedDetailsViewModel!
override func setUp() {
super.setUp()
feedService = FeedServiceMock()
states = []
viewModel = FeedViewModel(feedService)
viewModel.onState = { self.states.append($0) }
}
final class FeedDetailsViewModelTests: XCTestCase {
// …

func testLoadDataTransitionsToLoadedState() {
viewModel.loadData()
switch (states.first!, states.last!) {
case (.loading, .loaded):
break
default:
XCTFail()
}
}
}
final class FeedDetailsViewModelTests: XCTestCase {
// …

func testLoadDataTransitionsToLoadedState() {
viewModel.loadData()
switch (states.first!, states.last!) {
case (.loading, .loaded):
break
default:
XCTFail()
}
}
}
final class FeedDetailsViewModelTests: XCTestCase {
// …

func testLoadDataTransitionsToLoadedState() {
viewModel.loadData()
switch (states.first!, states.last!) {
case (.loading, .loaded):
break
default:
XCTFail()
}
}
}
final class FeedDetailsViewModelTests: XCTestCase {
// …

func testLoadDataTransitionsToLoadedState() {
viewModel.loadData()
switch (states.first!, states.last!) {
case (.loading, .loaded):
break
default:
XCTFail()
}
}
}
final class FeedDetailsViewModelTests: XCTestCase {
// …

func testFeedItemData() {
viewModel.loadData()
switch states.last! {
case .loaded(let data):
XCTAssertEqual(data, self.feedService.mockFeedItems)
default:
XCTFail("Expected `loaded`")
}
}
}
final class FeedDetailsViewModelTests: XCTestCase {
// …

func testFeedItemData() {
viewModel.loadData()
switch states.last! {
case .loaded(let data):
XCTAssertEqual(data, self.feedService.mockFeedItems)
default:
XCTFail("Expected `loaded`")
}
}
}
final class FeedDetailsViewModelTests: XCTestCase {
// …

func testFeedItemData() {
viewModel.loadData()
switch states.last! {
case .loaded(let data):
XCTAssertEqual(data, self.feedService.mockFeedItems)
default:
XCTFail("Expected `loaded`")
}
}
}
final class FeedDetailsViewModelTests: XCTestCase {
// …

func testFeedItemData() {
viewModel.loadData()
switch states.last! {
case .loaded(let data):
XCTAssertEqual(data, self.feedService.mockFeedItems)
default:
XCTFail("Expected `loaded`")
}
}
}
Rinse and

repeat.
Dependencyji
Stub / mock
Preuzeti kontrolu nad
dependencyjem
Lakše testiranje
1.
Dependency

Injection
class PersistenceService {
var token: String? {
let defaults = UserDefaults.standard
return defaults.object(forKey: "user_token") as? String
}
}
class PersistenceService {
var token: String? {
let defaults = UserDefaults.standard
return defaults.object(forKey: "user_token") as? String
}
}
Implicitni dependency
class PersistenceService {
private let defaults: UserDefaults
init(_ defaults: UserDefaults) {
self.defaults = defaults
}
var token: String? {
return defaults.object(forKey: "user_token") as? String
}
}
Pozivatelj

kreira 

dependency
2.
Dependency

Inversion
class PersistenceService {
private let defaults: UserDefaults
init(_ defaults: UserDefaults) {
self.defaults = defaults
}
var token: String? {
return defaults.object(forKey: "user_token") as? String
}
}
protocol ObjectStore {
func set(value: Any?, forKey: String)
func object(forKey: String)-> Any?
}
protocol ObjectStore {
func set(value: Any?, forKey: String)
func object(forKey: String)-> Any?
}
extension UserDefaults: ObjectStore {}
class PersistenceService {
private let defaults: ObjectStore
init(_ defaults: ObjectStore) {
self.defaults = defaults
}
var token: String? {
return defaults.object(forKey: "user_token") as? String
}
}
class UserDefaultsMock: ObjectStore {
func object(forKey: String) -> Any? {
}
func set(value: Any?, forKey: String) {
}
}
let userDefaultsMock = UserDefaultsMock()
let persistenceService = PersistenceService(userDefaultsMock)
class UserDefaultsMock: ObjectStore {
var data: [String: Any?] = [:]
func object(forKey key: String) -> Any? {
return data[key] ?? nil
}
func set(value: Any?, forKey key: String) {
data[key] = value
}
}
final class PersistenceServiceTests: XCTestCase {
var store: ObjectStoreMock!
var service: PersistenceService!
override func setUp() {
super.setUp()
store = ObjectStoreMock()
service = PersistenceService(store)
}
func testRetrievesSavedTokenFromStore() {
store.data["token"] = "savedToken"
XCTAssertEqual(service.token, "savedToken")
}
}
Pisanje
mockova.
class LoginServiceMock: LoginServiceProtocol {
func login(username: String, password: String,
completion: @escaping (LoginResult)-> Void) {
}
}
class LoginServiceMock: LoginServiceProtocol {
var loginParameters: (username: String, password: String)?
func login(username: String, password: String,
completion: @escaping (LoginResult)-> Void) {
loginParameters = (username, password)
}
}
class LoginServiceMock: LoginServiceProtocol {
var loginParameters: (username: String, password: String)?
func login(username: String, password: String,
completion: @escaping (LoginResult)-> Void) {
loginParameters = (username, password)
}
}
class LoginServiceMock: LoginServiceProtocol {
var loginParameters: (username: String, password: String)?
func login(username: String, password: String,
completion: @escaping (LoginResult)-> Void) {
loginParameters = (username, password)
}
}
func testCallsLoginServiceWithCorrectParams() {
loginViewModel.login(

email: "email@mail.com", 

password: "123pass")
let expectedParams = ("email@mail.com", "123pass")
XCTAssertEqual(expectedParams,

loginServiceMock.loginParameters)
}
var loginShouldSucceed = true
func login(username: String, password: String,
completion: @escaping (LoginResult)-> Void) {
if loginShouldSucceed {
completion(.success(UserToken(token: "abc123")))
} else {
completion(.failure(.noInternet))
}
}
var loginShouldSucceed = true
func login(username: String, password: String,
completion: @escaping (LoginResult)-> Void) {
if loginShouldSucceed {
completion(.success(UserToken(token: "abc123")))
} else {
completion(.failure(.noInternet))
}
}
var loginShouldSucceed = true
func login(username: String, password: String,
completion: @escaping (LoginResult)-> Void) {
if loginShouldSucceed {
completion(.success(UserToken(token: "abc123")))
} else {
completion(.failure(.noInternet))
}
}
func testHandlesErrorCorrectly() {
loginServiceMock.loginShouldSucceed = false
loginViewModel.login(email: "mail@mail.com", 

password: "123pass")
XCTAssertNotNil(viewModel.errorText)
}
Sourcery je
prijatelj.
Link na kraju preze.
Pisanje testova
Testovi su
teški.
Dobri testovi
su teški.
Ne prolazi za ni jednu netočnu
implementaciju.
1. Pokrivenost
func testHandlesErrorCorrectly() {
loginServiceMock.loginShouldSucceed = false
loginViewModel.login(email: "mail@mail.com", 

password: "123pass")
XCTAssertNotNil(viewModel.errorText)
}
Prazan string?
Test prolazi za sve korektne
implementacije.
1. Lakoća
refaktoringa
func testStoresUsernameCorrectly() {
let store = UserDataStore()
store.store(username: "Marin")
XCTAssertEqual(store.storage["username"], "Marin")
}
func testStoresUsernameCorrectly() {
let store = UserDataStore()
store.store(username: "Marin")
XCTAssertEqual(store.storage["username"], "Marin")
}
func testStoresUsernameCorrectly() {
let store = UserDataStore()
store.store(username: "Marin")
XCTAssertEqual(store.storedUsername, "Marin")
}
vs
Korektno
+
Fleksibilno
Tips & tricks
Odaberi dobar
framework
Nek te CI
natjera
Piši helpere
Testiraj nešto
Whew!
Testing For People Who Hate Testing

https://eev.ee/blog/2016/08/22/testing-for-people-who-hate-testing/
AutoMockable Sourcery template

https://cdn.rawgit.com/krzysztofzablocki/Sourcery/master/docs/mocks.html
Unit Testing in Swift

https://medium.cobeisfresh.com/unit-testing-in-swift-part-1-the-philosophy-9bc85ed5001b
Ad

More Related Content

What's hot (20)

Architectures in the compose world
Architectures in the compose worldArchitectures in the compose world
Architectures in the compose world
Fabio Collini
 
Drupal8Day: Demystifying Drupal 8 Ajax Callback commands
Drupal8Day: Demystifying Drupal 8 Ajax Callback commandsDrupal8Day: Demystifying Drupal 8 Ajax Callback commands
Drupal8Day: Demystifying Drupal 8 Ajax Callback commands
Michael Miles
 
Exercícios Netbeans - Vera Cymbron
Exercícios Netbeans - Vera CymbronExercícios Netbeans - Vera Cymbron
Exercícios Netbeans - Vera Cymbron
cymbron
 
Selenium Webdriver with data driven framework
Selenium Webdriver with data driven frameworkSelenium Webdriver with data driven framework
Selenium Webdriver with data driven framework
David Rajah Selvaraj
 
Simplified Android Development with Simple-Stack
Simplified Android Development with Simple-StackSimplified Android Development with Simple-Stack
Simplified Android Development with Simple-Stack
Gabor Varadi
 
Net Beans Codes for Student Portal
Net Beans Codes for Student PortalNet Beans Codes for Student Portal
Net Beans Codes for Student Portal
Peeyush Ranjan
 
Demystifying AJAX Callback Commands in Drupal 8
Demystifying AJAX Callback Commands in Drupal 8Demystifying AJAX Callback Commands in Drupal 8
Demystifying AJAX Callback Commands in Drupal 8
Michael Miles
 
Don't Make Android Bad... Again
Don't Make Android Bad... AgainDon't Make Android Bad... Again
Don't Make Android Bad... Again
Pedro Vicente
 
Spring Certification Questions
Spring Certification QuestionsSpring Certification Questions
Spring Certification Questions
SpringMockExams
 
Selenium my sql and junit user guide
Selenium my sql and junit user guideSelenium my sql and junit user guide
Selenium my sql and junit user guide
Fahad Shiekh
 
Build Widgets
Build WidgetsBuild Widgets
Build Widgets
scottw
 
E2E testing con nightwatch.js - Drupalcamp Spain 2018
E2E testing con nightwatch.js  - Drupalcamp Spain 2018E2E testing con nightwatch.js  - Drupalcamp Spain 2018
E2E testing con nightwatch.js - Drupalcamp Spain 2018
Salvador Molina (Slv_)
 
Introduction to Redux
Introduction to ReduxIntroduction to Redux
Introduction to Redux
Ignacio Martín
 
React lecture
React lectureReact lecture
React lecture
Christoffer Noring
 
Advanced java practical semester 6_computer science
Advanced java practical semester 6_computer scienceAdvanced java practical semester 6_computer science
Advanced java practical semester 6_computer science
Niraj Bharambe
 
#18.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)_국비지원IT학원/실업자/재직자환급교육/자바/스프링/...
#18.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)_국비지원IT학원/실업자/재직자환급교육/자바/스프링/...#18.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)_국비지원IT학원/실업자/재직자환급교육/자바/스프링/...
#18.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)_국비지원IT학원/실업자/재직자환급교육/자바/스프링/...
탑크리에듀(구로디지털단지역3번출구 2분거리)
 
Converting Db Schema Into Uml Classes
Converting Db Schema Into Uml ClassesConverting Db Schema Into Uml Classes
Converting Db Schema Into Uml Classes
Kaniska Mandal
 
Sustaining Test-Driven Development
Sustaining Test-Driven DevelopmentSustaining Test-Driven Development
Sustaining Test-Driven Development
AgileOnTheBeach
 
Intro to Redux | DreamLab Academy #3
Intro to Redux | DreamLab Academy #3 Intro to Redux | DreamLab Academy #3
Intro to Redux | DreamLab Academy #3
DreamLab
 
Demystifying Drupal AJAX Callback Commands
Demystifying Drupal AJAX Callback CommandsDemystifying Drupal AJAX Callback Commands
Demystifying Drupal AJAX Callback Commands
Michael Miles
 
Architectures in the compose world
Architectures in the compose worldArchitectures in the compose world
Architectures in the compose world
Fabio Collini
 
Drupal8Day: Demystifying Drupal 8 Ajax Callback commands
Drupal8Day: Demystifying Drupal 8 Ajax Callback commandsDrupal8Day: Demystifying Drupal 8 Ajax Callback commands
Drupal8Day: Demystifying Drupal 8 Ajax Callback commands
Michael Miles
 
Exercícios Netbeans - Vera Cymbron
Exercícios Netbeans - Vera CymbronExercícios Netbeans - Vera Cymbron
Exercícios Netbeans - Vera Cymbron
cymbron
 
Selenium Webdriver with data driven framework
Selenium Webdriver with data driven frameworkSelenium Webdriver with data driven framework
Selenium Webdriver with data driven framework
David Rajah Selvaraj
 
Simplified Android Development with Simple-Stack
Simplified Android Development with Simple-StackSimplified Android Development with Simple-Stack
Simplified Android Development with Simple-Stack
Gabor Varadi
 
Net Beans Codes for Student Portal
Net Beans Codes for Student PortalNet Beans Codes for Student Portal
Net Beans Codes for Student Portal
Peeyush Ranjan
 
Demystifying AJAX Callback Commands in Drupal 8
Demystifying AJAX Callback Commands in Drupal 8Demystifying AJAX Callback Commands in Drupal 8
Demystifying AJAX Callback Commands in Drupal 8
Michael Miles
 
Don't Make Android Bad... Again
Don't Make Android Bad... AgainDon't Make Android Bad... Again
Don't Make Android Bad... Again
Pedro Vicente
 
Spring Certification Questions
Spring Certification QuestionsSpring Certification Questions
Spring Certification Questions
SpringMockExams
 
Selenium my sql and junit user guide
Selenium my sql and junit user guideSelenium my sql and junit user guide
Selenium my sql and junit user guide
Fahad Shiekh
 
Build Widgets
Build WidgetsBuild Widgets
Build Widgets
scottw
 
E2E testing con nightwatch.js - Drupalcamp Spain 2018
E2E testing con nightwatch.js  - Drupalcamp Spain 2018E2E testing con nightwatch.js  - Drupalcamp Spain 2018
E2E testing con nightwatch.js - Drupalcamp Spain 2018
Salvador Molina (Slv_)
 
Advanced java practical semester 6_computer science
Advanced java practical semester 6_computer scienceAdvanced java practical semester 6_computer science
Advanced java practical semester 6_computer science
Niraj Bharambe
 
#18.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)_국비지원IT학원/실업자/재직자환급교육/자바/스프링/...
#18.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)_국비지원IT학원/실업자/재직자환급교육/자바/스프링/...#18.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)_국비지원IT학원/실업자/재직자환급교육/자바/스프링/...
#18.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)_국비지원IT학원/실업자/재직자환급교육/자바/스프링/...
탑크리에듀(구로디지털단지역3번출구 2분거리)
 
Converting Db Schema Into Uml Classes
Converting Db Schema Into Uml ClassesConverting Db Schema Into Uml Classes
Converting Db Schema Into Uml Classes
Kaniska Mandal
 
Sustaining Test-Driven Development
Sustaining Test-Driven DevelopmentSustaining Test-Driven Development
Sustaining Test-Driven Development
AgileOnTheBeach
 
Intro to Redux | DreamLab Academy #3
Intro to Redux | DreamLab Academy #3 Intro to Redux | DreamLab Academy #3
Intro to Redux | DreamLab Academy #3
DreamLab
 
Demystifying Drupal AJAX Callback Commands
Demystifying Drupal AJAX Callback CommandsDemystifying Drupal AJAX Callback Commands
Demystifying Drupal AJAX Callback Commands
Michael Miles
 

Similar to iOS Talks 6: Unit Testing (20)

Writing Your App Swiftly
Writing Your App SwiftlyWriting Your App Swiftly
Writing Your App Swiftly
Sommer Panage
 
Asp.NET MVC
Asp.NET MVCAsp.NET MVC
Asp.NET MVC
vrluckyin
 
React state managmenet with Redux
React state managmenet with ReduxReact state managmenet with Redux
React state managmenet with Redux
Vedran Blaženka
 
Controllers & actions
Controllers & actionsControllers & actions
Controllers & actions
Eyal Vardi
 
Building Testable Reactive Apps with MVI
Building Testable Reactive Apps with MVIBuilding Testable Reactive Apps with MVI
Building Testable Reactive Apps with MVI
James Shvarts
 
Cocoa heads testing and viewcontrollers
Cocoa heads testing and viewcontrollersCocoa heads testing and viewcontrollers
Cocoa heads testing and viewcontrollers
Stijn Willems
 
Asp.net mvc training
Asp.net mvc trainingAsp.net mvc training
Asp.net mvc training
icubesystem
 
Swift Delhi: Practical POP
Swift Delhi: Practical POPSwift Delhi: Practical POP
Swift Delhi: Practical POP
Natasha Murashev
 
Core Data with Swift 3.0
Core Data with Swift 3.0Core Data with Swift 3.0
Core Data with Swift 3.0
Korhan Bircan
 
Single page webapps & javascript-testing
Single page webapps & javascript-testingSingle page webapps & javascript-testing
Single page webapps & javascript-testing
smontanari
 
JDBC for CSQL Database
JDBC for CSQL DatabaseJDBC for CSQL Database
JDBC for CSQL Database
jitendral
 
20150516 modern web_conf_tw
20150516 modern web_conf_tw20150516 modern web_conf_tw
20150516 modern web_conf_tw
Tse-Ching Ho
 
Windows Store app using XAML and C#: Enterprise Product Development
Windows Store app using XAML and C#: Enterprise Product Development Windows Store app using XAML and C#: Enterprise Product Development
Windows Store app using XAML and C#: Enterprise Product Development
Mahmoud Hamed Mahmoud
 
[Final] ReactJS presentation
[Final] ReactJS presentation[Final] ReactJS presentation
[Final] ReactJS presentation
洪 鹏发
 
Event Sourcing - what could go wrong - Devoxx BE
Event Sourcing - what could go wrong - Devoxx BEEvent Sourcing - what could go wrong - Devoxx BE
Event Sourcing - what could go wrong - Devoxx BE
Andrzej Ludwikowski
 
Easy tests with Selenide and Easyb
Easy tests with Selenide and EasybEasy tests with Selenide and Easyb
Easy tests with Selenide and Easyb
Iakiv Kramarenko
 
Conditional fields - Olga Riabodzei
Conditional fields - Olga RiabodzeiConditional fields - Olga Riabodzei
Conditional fields - Olga Riabodzei
DrupalCamp Kyiv
 
Unit test candidate solutions
Unit test candidate solutionsUnit test candidate solutions
Unit test candidate solutions
benewu
 
React + Redux. Best practices
React + Redux.  Best practicesReact + Redux.  Best practices
React + Redux. Best practices
Clickky
 
Ngrx slides
Ngrx slidesNgrx slides
Ngrx slides
Christoffer Noring
 
Writing Your App Swiftly
Writing Your App SwiftlyWriting Your App Swiftly
Writing Your App Swiftly
Sommer Panage
 
React state managmenet with Redux
React state managmenet with ReduxReact state managmenet with Redux
React state managmenet with Redux
Vedran Blaženka
 
Controllers & actions
Controllers & actionsControllers & actions
Controllers & actions
Eyal Vardi
 
Building Testable Reactive Apps with MVI
Building Testable Reactive Apps with MVIBuilding Testable Reactive Apps with MVI
Building Testable Reactive Apps with MVI
James Shvarts
 
Cocoa heads testing and viewcontrollers
Cocoa heads testing and viewcontrollersCocoa heads testing and viewcontrollers
Cocoa heads testing and viewcontrollers
Stijn Willems
 
Asp.net mvc training
Asp.net mvc trainingAsp.net mvc training
Asp.net mvc training
icubesystem
 
Swift Delhi: Practical POP
Swift Delhi: Practical POPSwift Delhi: Practical POP
Swift Delhi: Practical POP
Natasha Murashev
 
Core Data with Swift 3.0
Core Data with Swift 3.0Core Data with Swift 3.0
Core Data with Swift 3.0
Korhan Bircan
 
Single page webapps & javascript-testing
Single page webapps & javascript-testingSingle page webapps & javascript-testing
Single page webapps & javascript-testing
smontanari
 
JDBC for CSQL Database
JDBC for CSQL DatabaseJDBC for CSQL Database
JDBC for CSQL Database
jitendral
 
20150516 modern web_conf_tw
20150516 modern web_conf_tw20150516 modern web_conf_tw
20150516 modern web_conf_tw
Tse-Ching Ho
 
Windows Store app using XAML and C#: Enterprise Product Development
Windows Store app using XAML and C#: Enterprise Product Development Windows Store app using XAML and C#: Enterprise Product Development
Windows Store app using XAML and C#: Enterprise Product Development
Mahmoud Hamed Mahmoud
 
[Final] ReactJS presentation
[Final] ReactJS presentation[Final] ReactJS presentation
[Final] ReactJS presentation
洪 鹏发
 
Event Sourcing - what could go wrong - Devoxx BE
Event Sourcing - what could go wrong - Devoxx BEEvent Sourcing - what could go wrong - Devoxx BE
Event Sourcing - what could go wrong - Devoxx BE
Andrzej Ludwikowski
 
Easy tests with Selenide and Easyb
Easy tests with Selenide and EasybEasy tests with Selenide and Easyb
Easy tests with Selenide and Easyb
Iakiv Kramarenko
 
Conditional fields - Olga Riabodzei
Conditional fields - Olga RiabodzeiConditional fields - Olga Riabodzei
Conditional fields - Olga Riabodzei
DrupalCamp Kyiv
 
Unit test candidate solutions
Unit test candidate solutionsUnit test candidate solutions
Unit test candidate solutions
benewu
 
React + Redux. Best practices
React + Redux.  Best practicesReact + Redux.  Best practices
React + Redux. Best practices
Clickky
 
Ad

Recently uploaded (20)

How can one start with crypto wallet development.pptx
How can one start with crypto wallet development.pptxHow can one start with crypto wallet development.pptx
How can one start with crypto wallet development.pptx
laravinson24
 
Get & Download Wondershare Filmora Crack Latest [2025]
Get & Download Wondershare Filmora Crack Latest [2025]Get & Download Wondershare Filmora Crack Latest [2025]
Get & Download Wondershare Filmora Crack Latest [2025]
saniaaftab72555
 
Societal challenges of AI: biases, multilinguism and sustainability
Societal challenges of AI: biases, multilinguism and sustainabilitySocietal challenges of AI: biases, multilinguism and sustainability
Societal challenges of AI: biases, multilinguism and sustainability
Jordi Cabot
 
Adobe Marketo Engage Champion Deep Dive - SFDC CRM Synch V2 & Usage Dashboards
Adobe Marketo Engage Champion Deep Dive - SFDC CRM Synch V2 & Usage DashboardsAdobe Marketo Engage Champion Deep Dive - SFDC CRM Synch V2 & Usage Dashboards
Adobe Marketo Engage Champion Deep Dive - SFDC CRM Synch V2 & Usage Dashboards
BradBedford3
 
Landscape of Requirements Engineering for/by AI through Literature Review
Landscape of Requirements Engineering for/by AI through Literature ReviewLandscape of Requirements Engineering for/by AI through Literature Review
Landscape of Requirements Engineering for/by AI through Literature Review
Hironori Washizaki
 
Revolutionizing Residential Wi-Fi PPT.pptx
Revolutionizing Residential Wi-Fi PPT.pptxRevolutionizing Residential Wi-Fi PPT.pptx
Revolutionizing Residential Wi-Fi PPT.pptx
nidhisingh691197
 
Secure Test Infrastructure: The Backbone of Trustworthy Software Development
Secure Test Infrastructure: The Backbone of Trustworthy Software DevelopmentSecure Test Infrastructure: The Backbone of Trustworthy Software Development
Secure Test Infrastructure: The Backbone of Trustworthy Software Development
Shubham Joshi
 
LEARN SEO AND INCREASE YOUR KNOWLDGE IN SOFTWARE INDUSTRY
LEARN SEO AND INCREASE YOUR KNOWLDGE IN SOFTWARE INDUSTRYLEARN SEO AND INCREASE YOUR KNOWLDGE IN SOFTWARE INDUSTRY
LEARN SEO AND INCREASE YOUR KNOWLDGE IN SOFTWARE INDUSTRY
NidaFarooq10
 
TestMigrationsInPy: A Dataset of Test Migrations from Unittest to Pytest (MSR...
TestMigrationsInPy: A Dataset of Test Migrations from Unittest to Pytest (MSR...TestMigrationsInPy: A Dataset of Test Migrations from Unittest to Pytest (MSR...
TestMigrationsInPy: A Dataset of Test Migrations from Unittest to Pytest (MSR...
Andre Hora
 
How Valletta helped healthcare SaaS to transform QA and compliance to grow wi...
How Valletta helped healthcare SaaS to transform QA and compliance to grow wi...How Valletta helped healthcare SaaS to transform QA and compliance to grow wi...
How Valletta helped healthcare SaaS to transform QA and compliance to grow wi...
Egor Kaleynik
 
Solidworks Crack 2025 latest new + license code
Solidworks Crack 2025 latest new + license codeSolidworks Crack 2025 latest new + license code
Solidworks Crack 2025 latest new + license code
aneelaramzan63
 
How to Optimize Your AWS Environment for Improved Cloud Performance
How to Optimize Your AWS Environment for Improved Cloud PerformanceHow to Optimize Your AWS Environment for Improved Cloud Performance
How to Optimize Your AWS Environment for Improved Cloud Performance
ThousandEyes
 
Meet the Agents: How AI Is Learning to Think, Plan, and Collaborate
Meet the Agents: How AI Is Learning to Think, Plan, and CollaborateMeet the Agents: How AI Is Learning to Think, Plan, and Collaborate
Meet the Agents: How AI Is Learning to Think, Plan, and Collaborate
Maxim Salnikov
 
Adobe Lightroom Classic Crack FREE Latest link 2025
Adobe Lightroom Classic Crack FREE Latest link 2025Adobe Lightroom Classic Crack FREE Latest link 2025
Adobe Lightroom Classic Crack FREE Latest link 2025
kashifyounis067
 
Interactive odoo dashboards for sales, CRM , Inventory, Invoice, Purchase, Pr...
Interactive odoo dashboards for sales, CRM , Inventory, Invoice, Purchase, Pr...Interactive odoo dashboards for sales, CRM , Inventory, Invoice, Purchase, Pr...
Interactive odoo dashboards for sales, CRM , Inventory, Invoice, Purchase, Pr...
AxisTechnolabs
 
Salesforce Data Cloud- Hyperscale data platform, built for Salesforce.
Salesforce Data Cloud- Hyperscale data platform, built for Salesforce.Salesforce Data Cloud- Hyperscale data platform, built for Salesforce.
Salesforce Data Cloud- Hyperscale data platform, built for Salesforce.
Dele Amefo
 
Adobe Master Collection CC Crack Advance Version 2025
Adobe Master Collection CC Crack Advance Version 2025Adobe Master Collection CC Crack Advance Version 2025
Adobe Master Collection CC Crack Advance Version 2025
kashifyounis067
 
Requirements in Engineering AI- Enabled Systems: Open Problems and Safe AI Sy...
Requirements in Engineering AI- Enabled Systems: Open Problems and Safe AI Sy...Requirements in Engineering AI- Enabled Systems: Open Problems and Safe AI Sy...
Requirements in Engineering AI- Enabled Systems: Open Problems and Safe AI Sy...
Lionel Briand
 
How to Batch Export Lotus Notes NSF Emails to Outlook PST Easily?
How to Batch Export Lotus Notes NSF Emails to Outlook PST Easily?How to Batch Export Lotus Notes NSF Emails to Outlook PST Easily?
How to Batch Export Lotus Notes NSF Emails to Outlook PST Easily?
steaveroggers
 
WinRAR Crack for Windows (100% Working 2025)
WinRAR Crack for Windows (100% Working 2025)WinRAR Crack for Windows (100% Working 2025)
WinRAR Crack for Windows (100% Working 2025)
sh607827
 
How can one start with crypto wallet development.pptx
How can one start with crypto wallet development.pptxHow can one start with crypto wallet development.pptx
How can one start with crypto wallet development.pptx
laravinson24
 
Get & Download Wondershare Filmora Crack Latest [2025]
Get & Download Wondershare Filmora Crack Latest [2025]Get & Download Wondershare Filmora Crack Latest [2025]
Get & Download Wondershare Filmora Crack Latest [2025]
saniaaftab72555
 
Societal challenges of AI: biases, multilinguism and sustainability
Societal challenges of AI: biases, multilinguism and sustainabilitySocietal challenges of AI: biases, multilinguism and sustainability
Societal challenges of AI: biases, multilinguism and sustainability
Jordi Cabot
 
Adobe Marketo Engage Champion Deep Dive - SFDC CRM Synch V2 & Usage Dashboards
Adobe Marketo Engage Champion Deep Dive - SFDC CRM Synch V2 & Usage DashboardsAdobe Marketo Engage Champion Deep Dive - SFDC CRM Synch V2 & Usage Dashboards
Adobe Marketo Engage Champion Deep Dive - SFDC CRM Synch V2 & Usage Dashboards
BradBedford3
 
Landscape of Requirements Engineering for/by AI through Literature Review
Landscape of Requirements Engineering for/by AI through Literature ReviewLandscape of Requirements Engineering for/by AI through Literature Review
Landscape of Requirements Engineering for/by AI through Literature Review
Hironori Washizaki
 
Revolutionizing Residential Wi-Fi PPT.pptx
Revolutionizing Residential Wi-Fi PPT.pptxRevolutionizing Residential Wi-Fi PPT.pptx
Revolutionizing Residential Wi-Fi PPT.pptx
nidhisingh691197
 
Secure Test Infrastructure: The Backbone of Trustworthy Software Development
Secure Test Infrastructure: The Backbone of Trustworthy Software DevelopmentSecure Test Infrastructure: The Backbone of Trustworthy Software Development
Secure Test Infrastructure: The Backbone of Trustworthy Software Development
Shubham Joshi
 
LEARN SEO AND INCREASE YOUR KNOWLDGE IN SOFTWARE INDUSTRY
LEARN SEO AND INCREASE YOUR KNOWLDGE IN SOFTWARE INDUSTRYLEARN SEO AND INCREASE YOUR KNOWLDGE IN SOFTWARE INDUSTRY
LEARN SEO AND INCREASE YOUR KNOWLDGE IN SOFTWARE INDUSTRY
NidaFarooq10
 
TestMigrationsInPy: A Dataset of Test Migrations from Unittest to Pytest (MSR...
TestMigrationsInPy: A Dataset of Test Migrations from Unittest to Pytest (MSR...TestMigrationsInPy: A Dataset of Test Migrations from Unittest to Pytest (MSR...
TestMigrationsInPy: A Dataset of Test Migrations from Unittest to Pytest (MSR...
Andre Hora
 
How Valletta helped healthcare SaaS to transform QA and compliance to grow wi...
How Valletta helped healthcare SaaS to transform QA and compliance to grow wi...How Valletta helped healthcare SaaS to transform QA and compliance to grow wi...
How Valletta helped healthcare SaaS to transform QA and compliance to grow wi...
Egor Kaleynik
 
Solidworks Crack 2025 latest new + license code
Solidworks Crack 2025 latest new + license codeSolidworks Crack 2025 latest new + license code
Solidworks Crack 2025 latest new + license code
aneelaramzan63
 
How to Optimize Your AWS Environment for Improved Cloud Performance
How to Optimize Your AWS Environment for Improved Cloud PerformanceHow to Optimize Your AWS Environment for Improved Cloud Performance
How to Optimize Your AWS Environment for Improved Cloud Performance
ThousandEyes
 
Meet the Agents: How AI Is Learning to Think, Plan, and Collaborate
Meet the Agents: How AI Is Learning to Think, Plan, and CollaborateMeet the Agents: How AI Is Learning to Think, Plan, and Collaborate
Meet the Agents: How AI Is Learning to Think, Plan, and Collaborate
Maxim Salnikov
 
Adobe Lightroom Classic Crack FREE Latest link 2025
Adobe Lightroom Classic Crack FREE Latest link 2025Adobe Lightroom Classic Crack FREE Latest link 2025
Adobe Lightroom Classic Crack FREE Latest link 2025
kashifyounis067
 
Interactive odoo dashboards for sales, CRM , Inventory, Invoice, Purchase, Pr...
Interactive odoo dashboards for sales, CRM , Inventory, Invoice, Purchase, Pr...Interactive odoo dashboards for sales, CRM , Inventory, Invoice, Purchase, Pr...
Interactive odoo dashboards for sales, CRM , Inventory, Invoice, Purchase, Pr...
AxisTechnolabs
 
Salesforce Data Cloud- Hyperscale data platform, built for Salesforce.
Salesforce Data Cloud- Hyperscale data platform, built for Salesforce.Salesforce Data Cloud- Hyperscale data platform, built for Salesforce.
Salesforce Data Cloud- Hyperscale data platform, built for Salesforce.
Dele Amefo
 
Adobe Master Collection CC Crack Advance Version 2025
Adobe Master Collection CC Crack Advance Version 2025Adobe Master Collection CC Crack Advance Version 2025
Adobe Master Collection CC Crack Advance Version 2025
kashifyounis067
 
Requirements in Engineering AI- Enabled Systems: Open Problems and Safe AI Sy...
Requirements in Engineering AI- Enabled Systems: Open Problems and Safe AI Sy...Requirements in Engineering AI- Enabled Systems: Open Problems and Safe AI Sy...
Requirements in Engineering AI- Enabled Systems: Open Problems and Safe AI Sy...
Lionel Briand
 
How to Batch Export Lotus Notes NSF Emails to Outlook PST Easily?
How to Batch Export Lotus Notes NSF Emails to Outlook PST Easily?How to Batch Export Lotus Notes NSF Emails to Outlook PST Easily?
How to Batch Export Lotus Notes NSF Emails to Outlook PST Easily?
steaveroggers
 
WinRAR Crack for Windows (100% Working 2025)
WinRAR Crack for Windows (100% Working 2025)WinRAR Crack for Windows (100% Working 2025)
WinRAR Crack for Windows (100% Working 2025)
sh607827
 
Ad

iOS Talks 6: Unit Testing