Äntligen här! Kommande Liferay CE 6.3 kommer med support för att visa annonser integrerat direkt i portalen! Förhoppningsvis kan det med hjälp av cookies utifrån Google och Facebook ge riktad reklam, som passar den inloggade användaren bäst.

Citat:

"Due to the cost involved in producing CE releases we've decided to make this and future community releases ad-supported. What does this mean? It means you'll start seeing advertisements from our sponsors and related products within Liferay and on websites built with Liferay (see screenshots below). And best of all, this is a completely free service for you. Ad revenue will go directly to Liferay and used for improving Liferay, and occasionally used for important executives on important business meetings using a new corporate jet we've leased." (Länk)

 

Ett av de roligare April-skämten idag? Tycker iallafall jag :) Riktigt kul och kreativt av Liferay! Såvida det fortfarande inte skulle stå samma sak imorgon :)

Microsoft utvecklar just nu efterföljaren till Internet Explorer som för tillfället går under arbetsnamnet Project Spartan (msdn.com) och ska finnas tillgänglig i Windows 10. Den nya webbläsaren kommer inte att ersätta IE i Windows 10 utan IE kommer att leva vidare en tid framöver, vilket kan jämföras med hur Windows XP fortsatte att leva vidare en tid innan den slutade supportas. Den nya webbläsaren ska gå under ett nytt namn som ännu inte bestämts/avslöjats. Läs mer här (sophos.com).

 

Anno 2015 har även de flesta större systemutvecklade företag tagit sig så pass långt i mognadsnivå att någon form av agilmetodik tillämpas. Den vanligast förekommande metodiken idag är utan tvekan Scrum.  Låt oss för enkelhetensskull anta att man valt att applicera en klassisk tvånivåsmodell för ärendehantering: Product backlog item (PBI) och uppgift.  En PBI kan ha noll till många uppgifter; oftast ett par stycken. Denna modell är inte tänkt att vara komplett utan främst vara en grund för resonemanget kring Definition of Done (DoD).

Definition av Definition of Done (DoD)

Definition of Done är något som beskriver när en PBI och dess ingående uppgifter anses klara av Scrum -teamet.  Eftersom Produktägaren ingår i teamet så känner även denne till DoD och förstår dess innebörd.

DoDens konsumenter

Den är till för att skapa transparens inom Scrum -teamet (men kan även användas av produktägaren för att spegla status mot stakeholders). Det är därför centralt att alla i teamet förstår vad DoD innebär för de olika typer av aktivteter som teamet åtar sig. Jobbar man i ett företag där flera Scrum -team jobbar i en och samma produkt så behöver det finnas en gemensam DoD för att undvika tråkiga överraskningar i kritiska lägen. Reflektera själv över hur det kan sluta om TeamX har sin DoD och teamY har en helt annant och deras kod sedan ska sammanstråla. Kommer det smärtfritt om deras ändringar överlappar?

DoD behövs

Studier visar att en överväldigande majoritet av alla människor uppskattar att känna att de gör konkret nytta och de tar sig framåt med åtagna uppgifter. Utan en DoD hur ska man någonsin veta när man är klar? Hur ska någon annan veta? Hur ska hen få en känsla för hur hen ligger till?
Således är DoD inte bara viktigt för teamet utan även för individen.

En DoD per typ

Det är viktigt att särskilja mellan DoD för en PBI och dess uppgifter. En uppgift är en väldefinierad avgränsad del av det som behöver göras för att förverkliga PBIn.  Det är av yttersta vikt att alla i teamet förstår innebörden av varje uppgift och dess DoD. Har man inte förstått vad som ska göras eller när det anses klart blir det svårt att uppskatta insatsen som krävs.
Det samma gäller givetvis PBIn. Om den inte går att göra väldefinierad under en grooming eller Sprint-planering är PBIn sannolikt inte mogen för att ingå i en Sprint ännu.

Vår DoD håller inte

Givetvis får man återvända till sin DoD och justera den efterhand. Det är till och med rekommenderat. Se dock till att inte justera den under pågående Sprint! Det kan skapa total förvirring i ledet. Insikterna teamet får efter att ha arbetat tillsammans är guld värda. Det är en av anledningarna till att ”statiska” team är så högt värderad i den agila världen.  
Se således inte er DoD som slutgiltig utan ett pågående arbete.
Kom ihåg:
Det enda som är konstant i världen är förändring!

Skrev i ett tidigare inlägg om mockning på grund-nivå. Tänkte i detta inlägg beskriva partiell mockning; hur vi kan mocka en del av ett objekt, istället för ett helt objekt. Vi har en klass UserServiceImpl enligt nedan:

public class UserServiceImpl implements UserService {

   private UserDao userDao;

   public String createUser(User user) {
      …
      String code = generateUniqueCode();
      user.setCode(code);
      userDao.save(user);
      return code;
   }

   protected String generateUniqueCode () {
      …
   }

   public void setUserDao(UserDao userDao) {
      this.userDao = userDao;
   }
}

För att skriva ett test som mockar anropet till UserDao kan vi t ex göra enligt nedan (använder även här Mockito som mockningsramverk):

public class UserServiceCreateUserTest {
   @Test
   public void generatedCodeShouldBeReturnedWhenUserSaved() {
      UserServiceImpl userService = new UserServiceImpl();
      UserDao userDao = Mockito.mock(UserDao.class);
      userService.setUserDao(userDao);
      String result = userService.createUser(new UserImpl());
      //Utför något test
   }
}

I detta fallet har vi ett "riktig" objekt som är userService (genom new UserServiceImpl()) och ett mockat objekt som är userDao (genom mock(UserDao.class)). Från metoden createUser(User user) i UserServiceImpl görs anrop till en metod i UserServiceImpl (riktiga objektet) och en metod i UserDao (mockade objektet). Ibland så uppstår behov där det skulle förenkla att kunna mocka vissa metoder i ett ej mockad objekt, dvs att det riktiga objektet ska vara en sorts hybrid mellan ett riktigt objekt och ett mockat objekt; att vissa metoder i det ska vara "riktiga" medan andra är mockade.

Vi kan göra UserServiceImpl till en sådan hybrid genom tillämpa Spy i Mockito enligt nedan.

public class UserServiceCreateUserTest {
   @Test
   public void generatedCodeShouldBeReturnedWhenUserSaved() {
      UserServiceImpl userService = Mockito.spy(new UserServiceImpl());
      UserDao userDao = Mockito.mock(UserDao.class);
      userService.setUserDao(userDao);
      Mockito.doReturn("my mocked code").when(userService).generateUniqueCode();
      String result = userService.createUser(new UserImpl());
      //Utför något test
   }
}

I senaste exemplet så har vi ändra initialisering av userService genom att skicka in 'new UserServiceImpl()' som argument till spy-anrop. Detta betyder att userService kommer att bete sig precis likadant som i exemplet ovan, dvs vara ett riktigt objekt. När vi väljer att mocka ett av dess metoder så gör vi det genom doReturn enligt ovan. Detta betyder nu att alla metoder i userService är riktiga förutom generateUniqueCode() som är mockad och kommer i senaste testet att returnera "my mocked code".

Tänkte i detta inlägg fortsätt med TDD och visa hur man enkelt mockar bort beroenden för att på så sätt isolera det objekt som man vill testa.

Nedan har vi klassen CustomerManagerImpl som i metoden getCustomerFullName() gör ett anrop till findCustomer(int customerId) i CustomerLookupClient som den har ett beroende till. Sedan är den lite dummy-kod som konkatenerar ihop för- och efternamn för att sedan returnera dessa.

public class CustomerManagerImpl implements CustomerManager {

   private CustomerLookupClient customerLookupClient;

   public String getCustomerFullName(int customerId) {
      Customer customer = customerLookupClient.findCustomer(customerId);
      String fullName = customer.getFirstName() + " " + customer.getLastName();
      return fullName;
   }

   public void setCustomerLookupClient (CustomerLookupClient customerLookupClient) {
      this.customerLookupClient = customerLookupClient;
   }
}

Skulle vi skriva ett test på detta enligt nedan så skulle det kastas ett NullPointerException eftersom customerLookupClient ej har initialiserats. Dessutom har vi inget förväntat resultat att testa mot, så länge vi kör ett rent unit-test utan någon container etc (vilket vi helst vill).

public class CustomerManagerGetCustomerFullNameTest {
   @Test
   public void firstAndLastNameShouldBeConcatinatedFromFoundCustomer() {
      CustomerManager customerManager = new CustomerManagerImpl();
      String result = customerManager.getCustomerFullName(1);
      //Utföra ett test på ???
   }
}

Vad vid får göra i detta fall är att mocka bort beroendet till customerLookupClient och på så sätt isolera testandet till endast den logik som sker i CustomerManagerImpl. Detta gör vi med i detta fall manuell mockning (kommer även titta på användning av ramverk längre ner).

public class CustomerLookupClientMock implements CustomerLookupClient {
   public Customer findCustomer(int id) {
      Customer mock = new CustomerImpl("John", "Smith");
      return mock;
   }
}

Här är en (av flera) bra motivering till att jobba med interface. Vi skapar ett objekt som returnerar ett för oss på förhand känt värde. Nedan sätter vi customerLookupClient-beroendet till det mockade objektet. Här också en bra motivering till varför man alltid till initiera beroenden via setter-metoder eller konstruktor, för att möjliggöra testbarhet. Notera också att vi nu på båda sidor av =-tecknet behöver använda CustomerManagerImpl för att komma ut setter-metoden.

public class CustomerManagerGetCustomerFullNameTest {
   @Test
   public void firstAndLastNameShouldBeConcatinatedFromFoundCustomer() {
      CustomerManagerImpl customerManager = new CustomerManagerImpl();
      customerManager.setCustomerLookupClient(new CustomerLookupClientMock());
      String result = customerManager.getCustomerFullName(1);
      assertEquals(result, "John Smith");
   }
}

Vi kan även utöka mockade objektet till att ta in för- och efternamn i sin konstruktor för att exempelvis gör den användbar för flera fall. Att mocka manuellt kan bli lite besvärligt när projekten växer då de ska underhålla och det blir många rader för att sätta upp mockningsobjekt som används av flera tester. Därför ska vi till sista titta på hur vi slipper manuell mockning genom att tillämpa ramverket Mockito för detta. Här nedan är föregående test omskrivet till att använda Mockito för mockningen, vi slipper alltså skapa separata mockningsobjekt.

public class CustomerManagerGetCustomerFullNameTest {
   @Test
   public void firstAndLastNameShouldBeConcatinatedFromFoundCustomer() {
      CustomerManagerImpl customerManager = new CustomerManagerImpl();
      CustomerLookupClient customerLookupClient = Mockito.mock(CustomerLookupClient.class);
      Mockito.doReturn(new Customer("John", "Smith")).when(customerLookupClient).findCustomer(1);
      customerManager.setCustomerLookupClient(customerLookupClient);
      String result = customerManager.getCustomerFullName(1);
      assertEquals(result, "John Smith");
   }
}

 

RSS (Öppnar nytt fönster)
Visar 1-5 av 48 resultat.
av 10