nie rozwiązuj w testach jednostkowych problemów z testowanym kodem

Post on 25-May-2015

686 Views

Category:

Technology

1 Downloads

Preview:

Click to see full reader

DESCRIPTION

Grzegorz Gałęzowski - prezentacja z III edycji konferencji Quality Excites.

TRANSCRIPT

QUALITY EXCITES 201431 MAJA 2014

GRZEGORZ GAŁĘZOWSKIMOTOROLA SOLUTIONS

GRZEGORZ GAŁĘZOWSKIMOTOROLA SOLUTIONS

NIE ROZWIĄZUJ W TESTACHJEDNOSTKOWYCH PROBLEMÓW Z TESTOWANYM KODEM

BĘDZIE O...

TESTACH JEDNOSTKOWYCH

I PROJEKTOWANIU

ORAZ ICH ZWIĄZKU

NA 5 PRZYKŁADACH

TESTY W MOIM ŚWIECIE...

Lista TODOCzy zaimplementowałem wszystko?

AnalizaCzy wiem, co buduję?

Wykonywalna dokumentacjaCzego "klient" może od kodu oczekiwać?

ProjektowanieJak rozbić problem?

TESTY JEDNOSTKOWEDAWNIEJ I DZIŚ

"the tests must be kept to the same level of high quality as the production code. (...) Duplication must be eliminated from them."

Robert C. Martin

ROZWIĄZANIANA POZIOMIEAUTOMATYZACJI

METODY SETUP

[SetUp] public void SetTheStage(){ this.valueUsedEverywhere = 12;

}

DZIEDZICZENIE KLAS

[TestFixture] public class AuthorizationBehaviors : TestBase

METODY POMOCNICZE

message = createMessageFor("Ala");

JAKOŚĆ JEDNOSTKI:SPÓJNOŚĆ I POWIĄZANIA

SPÓJNOŚĆ ~ JEDNA RZECZ

A B

C D

AB

C D

SPÓJNOŚĆ ~ JEDNA RZECZ

AB

CD

SPÓJNOŚĆ ~ JEDNA RZECZ

POWIĄZANIA – KOGO KLASA ZNA?

A

B

C

D

MOCKI – "SYMULATORY" OBIEKTÓW

ATEST

SPÓJNOŚĆ I POWIĄZANIAA TESTY

TEST JEDNOSTKOWY TO KLIENT KODU

Jednostka

KlientTest

Test

TestTest

Test

Test

Test

ŹLE ZAPROJEKTOWANA JEDNOSTKA...

Jednostka

KlientTest

Test

TestTest

Test

Test

Test

...JEST TRUDNO TESTOWALNA

Jednostka

KlientTest

Test

TestTest

Test

Test

Test

SŁUCHAJ ŚLEPOSWOICH TESTÓW

KORZYŚCI Z ˶SŁUCHANIA TESTÓW˝

Lepszy design produktu• większa spójność• mniej powiązań

Lepsza utrzymywalność testów

PIĘĆ PRZYKŁADÓW

UWAGA! ZŁY KOD!

PRZYKŁAD 1:

NACHODZENIEZAKRESUTESTÓW

validation = new SanityValidation();

info = new PersonInfo(); info.Name = "Zenek"; info.Surname = "Kowalski"; info.Age = VALID_AGE;

Assert.DoesNotThrow( () => validation.Of(info));

validation = new SanityValidation();

info = new PersonInfo(); info.Name = "$"; info.Surname = "Kowalski"; info.Age = VALID_AGE;

Assert.Throws<InvalidValueException>(

() => validation.Of(info));

validation = new SanityValidation();

info = new PersonInfo(); info.Name = "Zenek"; info.Surname = "$"; info.Age = VALID_AGE;

Assert.Throws<InvalidValueException>(

() => validation.Of(info));

validation = new SanityValidation();

info = new PersonInfo(); info.Name = "Zenek"; info.Surname = "Kowalski"; info.Age = VALID_AGE – 1;

Assert.Throws<InvalidValueException>(

() => validation.Of(info));

PÓKI CO...

Name Surname Age

UTRZYMYWALNOŚĆ

Name Surname Age Country

Name Surname Age Country

UTRZYMYWALNOŚĆ

Wskazówka: Nachodzenie na siebie zakresów testów.

˶NADPISZ JEDNO POLE˝ - OK, ALE...

validation = new SanityValidation();

info = CreateValidPersonInfo();info.Name = CreateInvalidName();

Assert.Throws<InvalidValueException>(

() => validation.Of(info));

˶NADPISZ JEDNO POLE˝ - OK, ALE...

validation = new SanityValidation();

info = CreateValidPersonInfo();info.Name = CreateInvalidName();

Assert.Throws<InvalidValueException>(

() => validation.Of(info));

Wskazówka: Testy różnych zachowań

padają z tego samego powodu

MAŁA SPÓJNOŚĆ

SanityValidation

Walidacja Surname

Walidacja Age

Testy Surname

Testy Age

Of(x)

Testy Name Walidacja Name

Walidacja Surname

Walidacja Age

ZACHOWANIA SOBIE PRZESZKADZAJĄ

SanityValidationWalidacja Name

Walidacja Surname

Walidacja Age

Testy Surname

Testy Age

Of(x)

Testy Name

ZACHOWANIA SOBIE PRZESZKADZAJĄ

SanityValidation

Walidacja Surname

Walidacja AgeTesty Age

Of()

Testy Name Walidacja Name

Walidacja Surname

Walidacja Age

Testy Surname

ZACHOWANIA SOBIE PRZESZKADZAJĄ

SanityValidation

Walidacja Surname

Walidacja Age

Testy Surname Of(x)

Testy Name Walidacja Name

Walidacja Surname

Walidacja AgeTesty Age

PODZIAŁ LEPSZA SPOJNOSĆ

PartialValidations

Walidacja Name

Walidacja Surname

Walidacja Age

SanityValidation

Of(x)

PersonInfo

UWSPÓLNIENIE

SanityValidation PartialValidations

Walidacja Napisu

Walidacja Minimum

Of(x)

PersonInfo

MAMY DANE I FUNKCJĘ

SanityValidation PartialValidations

Walidacja Napisu

Walidacja Minimum

Of(x)

PersonInfo

LEPSZA ABSTRAKCJA

Person

Validate()

PartialValidations

Walidacja Napisu

Walidacja MinimumPersonInfo

TEST PERSON: UŻYWA WALIDACJI?

Person

Validate()

PersonInfo

Test Validate()

PartialValidations

Mock

TESTY WALIDACJI NAPISU

PartialValidations

Walidacja Napisu

Walidacja Minimum

Testy Napisu

Testy Minimum

TEST WALIDACJI MINIMUM

Validations

Walidacja MinimumTesty Minimum

Walidacja NapisuTesty Napisu

PRZYKŁAD 2:

KOMBINACJEFUNKCJONALNOŚCI

var processing = new MessageProcessing();

messageProcessing.Encryption = true;messageProcessing.Translation = true;messageProcessing.Compression = true;

processing.For(message);

...

...

var processing = new MessageProcessing();

messageProcessing.Encryption = true;messageProcessing.Translation = true;messageProcessing.Compression = true;

processing.For(message);

...

...

Wskazówka: Eksplozja Kombinacji

[TestCase(true, true, true)]public void ShouldProcessMessage( bool encrypt, bool translate, bool compress){processing = new MessageProcessing();processing.Encryption = encrypt;processing.Translation = translate;processing.Compression = compress;//...

[TestCase(true , true , true )][TestCase(false, true , true )][TestCase(true , false, true )][TestCase(true , true , false)][TestCase(false, false, true )][TestCase(true , false, false)][TestCase(false, true , false)][TestCase(false, false, false)]public void ShouldProcessMessage( bool encrypt, bool translate, bool compress)

ZBYT WIELE ODPOWIEDZIALNOŚCI

MessageProcessing

Walidacja Surname

Walidacja Age

For(msg)

Encryption

Translation

Compression

PODZIAŁ NA MNIEJSZE OBIEKTY

MessageProcessing

For(msg)

Encryption

Translation

Compression

WYŁĄCZANIE TRANSFORMACJI

MessageProcessing

For(msg)

NullEncryption

Translation

Compression

TEST PRZETWARZANIA - LEPIEJ, ALE...

MessageProcessing

For(msg)

(1)

(2)

(3)

TEST PRZETWARZANIA - LEPIEJ, ALE...

MessageProcessing

For(msg)Wskazówka:

Dużo różnych mocków na test

WSPÓLNY MIANOWNIK...

MessageProcessing

Encryption

Translation

Compression

For(msg)

PODZIAŁ OBIEKTÓW

MessageProcessing

For(m)

EncryptionTranslation Compression

TransformationTransformationTransformation

TEST PRZETWARZANIA – JESZCZE RAZ

MessageProcessing

For(m)

PRZYKŁAD 3:

ŁAŃCUCHY ZALEŻNOŚCI

MOCKI - LEGENDA

Utworzenie:mock = Substitute.For<Interface>()

Zaprogramowanie rezultatu wywołanie metody:mock.GetSomething().Returns(something);

system = Substitute.For<System>();radio = Substitute.For<Radio>();owner = Substitute.For<User>();

system.GetRadio(1).Returns(radio);radio.GetOwner().Returns(owner);owner.GetName().Returns(name);

ZESTAWIANIE ŁAŃCUCHA MOCKÓW

Test

Name

WSZYSTKO WIDOCZNE PUBLICZNIE

System

Radio

OwnerName

Klient

PROBLEM Z ZALEŻNOŚCIAMI

System

Radio

OwnerName

Klient

PROBLEM Z ZALEŻNOŚCIAMI

System

Radio

OwnerName

Klient

Wskazówka: mocki zwracające mocki

NAJPROSTSZE ROZWIĄZANIE

System

Radio

OwnerRadioOwnerName

Klient

ŁATWIEJSZE TESTY

RadioOwnerName

Klient

PRZYKŁAD 4:

MUSZĘ TESTOWAĆ PRYWATNE METODY

Obiekt

D()B()

C()

A()

- CHCĘ TESTOWAĆ PRYWATNĄ METODĘ

- ZRÓB TO PRZEZ PUBLICZNE API

Test Obiekt

B()

C()

A()

D()

- ALE ONA JEST NA TYLE ODRĘBNA...

Test 2 Obiekt

B()

C()

A()

D()

... ŻE CHCĘ JĄ TESTOWAĆ OSOBNO.

Test 2 Obiekt

B()

C()

A()

D()Wskazówka:

Chęć testowania prywatnych metod

- TO JĄ WYDZIEL!

Test 2 Obiekt

B()

C()

A()

InnyObiekt

D()

PRZYKŁAD 5:

CIĘŻKI KONTEKST

configData = new ConfigData();configData.GetHeader().SetStdState(StdState.SUBMITTED);configData.GetHeader().SetType(FileType.NECB);

ge1 = CreateGroupEntry(1, TALKGROUP, null, configData.Id);ge2 = CreateGroupEntry(2, TALKGROUP, null, configData.Id);ge3 = CreateGroupEntry(3, MULTIGROUP, null,

configData.Id);ge4 = CreateGroupEntry(4, MULTIGROUP, null,

configData.Id);ge5 = CreateGroupEntry(5, MULTIGROUP, null,

configData.Id);

talkgroup1 = CreateTalkgroup(1, 1, null, configData.Id);talkgroup2 = CreateTalkgroup(1, 3, null, configData.Id);talkgroup3 = CreateTalkgroup(2, 0, null, configData.Id);talkgroup4 = CreateTalkgroup(3, 5, null, configData.Id);

context = new ValidationObjectContext(configData);

configData = new ConfigData();configData.GetHeader().SetStdState(StdState.SUBMITTED);configData.GetHeader().SetType(FileType.NECB);

ge1 = CreateGroupEntry(1, TALKGROUP, null, configData.Id);ge2 = CreateGroupEntry(2, TALKGROUP, null, configData.Id);ge3 = CreateGroupEntry(3, MULTIGROUP, null,

configData.Id);ge4 = CreateGroupEntry(4, MULTIGROUP, null,

configData.Id);ge5 = CreateGroupEntry(5, MULTIGROUP, null,

configData.Id);

talkgroup1 = CreateTalkgroup(1, 1, null, configData.Id);talkgroup2 = CreateTalkgroup(1, 3, null, configData.Id);talkgroup3 = CreateTalkgroup(2, 0, null, configData.Id);talkgroup4 = CreateTalkgroup(3, 5, null, configData.Id);

context = new ValidationObjectContext(configData);

Wskazówka: pracochłonne ustawianie kontekstu

WNIOSKI

Słuchaj ślepo swoich testówUważaj na:

• eksplozje kombinacji• długie testy• testowanie prywatnych metod• mocki zwracające mocki• ciężki kontekst

Szukaj najpierw źródła problemu w designie

PYTANIA?

Słuchaj ślepo swoich testówUważaj na:

• eksplozje kombinacji• długie testy• testowanie prywatnych metod• mocki zwracające mocki• ciężki kontekst

Szukaj najpierw źródła problemu w designie

MOTOROLA, MOTO, MOTOROLA SOLUTIONS and the Stylized M Logo are trademarks or registered trademarks of Motorola Trademark Holdings, LLC and are used under license. All other trademarks are the property of their respective owners. © 2010 Motorola, Inc. All rights reserved.

iProtect Classification: Public

top related