블로그 이미지
개발자로서 현장에서 일하면서 새로 접하는 기술들이나 알게된 정보 등을 정리하기 위한 블로그입니다. 운 좋게 미국에서 큰 회사들의 프로젝트에서 컬설턴트로 일하고 있어서 새로운 기술들을 접할 기회가 많이 있습니다. 미국의 IT 프로젝트에서 사용되는 툴들에 대해 많은 분들과 정보를 공유하고 싶습니다.
솔웅

최근에 받은 트랙백

글 보관함

calendar

        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30  

[Arduino] 3rd project. 4X4X4 LED Light Cube

2017.06.05 10:22 | Posted by 솔웅


I've purchased 4X4X4 LED Light Cube kit from Aliexpress. ($3.79)

4X4X4 Blue LED Light Cube Kit 3D LED DIY Kit Electronic Suite for Arduino







You can get the instruction from here. but There is not enough information to complete the set.

Fortunately, got perfect info from this blog.

https://emalliab.wordpress.com/2015/07/24/icstation-4x4x4-led-cube-shield-for-arduino-hardware-build/

 https://emalliab.wordpress.com/2015/07/24/icstation-4x4x4-led-cube-shield-for-arduino-software/


So I've followed it and could complete the set like this.




This is the blog (2nd one) explained about the source code.


icStation 4x4x4 LED Cube Shield for Arduino – Software



July 24, 2015 at 10:31 pm (computers) ()


As described in my previous post, I now have a working (I’ve run the demo code!) icStation 4x4x4 LED cube shield connected up to an Arduino Uno.  Unfortunately as I started to dig around in the sample library, I just couldn’t quite work out how it was meant to address each plane of the cube.  Eventually I decided it wasn’t possible, due to a number of bugs in the code.


이전 게시물에서 설명한 것처럼, icStation 4x4x4 LED cube shield를 Arduino Uno에 연결하는 작업을 하고 있습니다. 불행하게도 샘플 라이브러리를 파고들 수록 큐브의 각 면을 지정하는 방법에 대해 이해하기가 더 어려워 졌습니다. 결국 해당 샘플 코드에 버그가 많아 제대로작동할 수 없다는 결론에 이르렀습니다.


The demo code worked as the code just showed the same pattern on each of the four planes.  This is largely because the initialisation routines set the four Ardunio data pins to low, and then never did anything else with them!  There is some mention of pins 16 and 17, but no mention of pins 18 and 19, and actually in the main display routines, there is nothing done to actually set any of these pins once initialisation is complete.  So at this point I decided to read a bit more about the 74HC595 and just go it alone.  Attached is the result.  Feel free to use as you see fit.


그 데모 코드는 4개의 면 각각이 동일한 패턴으로 보여지도록 작동하고 있습니다. 초기화 루틴이 4 개의 Ardunio 데이터 핀을 로우로 설정 한 후 그것을 아무곳에서도 사용하지 않습니다. 핀 16과 핀 17에 대해서는 언급이 있지만, 핀 18과 19에 대한 언급이 없습니다, 메인 디스플레이 루틴에서, 초기화가 완료되면 실제로 이러한 핀들을 설정하는 일은 없습니다. 그래서 이 시점에서 필자는 74HC595에 대해 좀 더 읽고 혼자서 결정했습니다. 첨부 된 결과입니다. 이것을 토대로 당신이 적합하다고 생각하는대로 자유롭게 사용하십시오.


Basic initialisation


The two shift registers seem fairly simple to setup.  The Arduino needs some control pins setting up as outputs alongside the four digital outs used for the LEDs.  The initialisation is quite straight forward as follows:


두 개의 시프트 레지스터는 설정하는 것이 매우 간단합니다. Arduino는 LED에 사용되는 4 개의 디지털 출력과 함께 출력으로 설정되는 일부 제어 핀을 필요로합니다. 초기화는 다음과 같이 매우 간단합니다.


#include <Arduino.h>

int HC595_clockPin=0;   // SH_CP of 74HC595 
int HC595_latchPin=1;   // ST_CP of 74HC595 
int HC595_dataPin=3;    // DS of 74HC595 
int HC595_enablePin=2;  // Not OE of 74HC595
int LED_Pin16= 4;
int LED_Pin17= 5;
int LED_Pin18= 6;
int LED_Pin19= 7;

void setup() {
  // put your setup code here, to run once:
  pinMode( HC595_latchPin,  OUTPUT );
  pinMode( HC595_clockPin,  OUTPUT );
  pinMode( HC595_dataPin,   OUTPUT );
  pinMode( HC595_enablePin, OUTPUT );
  
  pinMode( LED_Pin16, OUTPUT );
  pinMode( LED_Pin17, OUTPUT );
  pinMode( LED_Pin18, OUTPUT );
  pinMode( LED_Pin19, OUTPUT );
  
  digitalWrite(LED_Pin16,HIGH);
  digitalWrite(LED_Pin17,HIGH);
  digitalWrite(LED_Pin18,HIGH);
  digitalWrite(LED_Pin19,HIGH);
//  digitalWrite(HC595_enablePin, LOW);  // Enable Not OE (negative logic)
}


I never did quite work out if I needed to do anything with the enable pin, but as it is active low, I assumed that by not doing anything, everything would be enabled by default anyway.

enable pin과 관련해서는 아무것도 하지 않았습니다. active 상태 값이 low 이기 때문입니다. 이렇게 아무것도 정의하지 않으면 디폴트로  enable이 될 것으로 생각 됩니다.


In terms of actually writing a value to the 74HC595, again that is fairly straight forward.

74HC595에 적용된 값들은 그냥 보시는 대로 입니다. 



/*
  Protocol for sending the data to the hc595 is as follows:
   (see: http://www.arduino.cc/en/Tutorial/ShiftOut)
   
   "when the clock pin goes from low to high, the shift register
    reads the state of the data pin ... when the latch pin goes
    from low to high the sent data gets moved from the shift
    registers ... to the output pins"
   
   As we have two HC595s chained together, we use a 16 bit input value
*/
void write_74HC595 (unsigned int hc595value) { 
   digitalWrite(HC595_latchPin, LOW);   // ensures LEDs don't light whilst changing values
   
   // Shift each 8 bit value in sequence - the two chained HC595s automatically grab
   // the right bits - the first 8 to the first chip, second 8 to the second chip
   shiftOut(HC595_dataPin, HC595_clockPin, LSBFIRST, hc595value);  
   shiftOut(HC595_dataPin, HC595_clockPin, LSBFIRST, (hc595value >> 8));
   
   digitalWrite(HC595_latchPin, HIGH);  // data transferred from shift register to outputs when latch goes LOW->HIGH
}


So 16 bits of the hc595value variable are sent in two 8-bit chunks over the serial port to the shift registers and with the appropriate signalling via the latch pin, that is basically that.  This sets the outputs of the 74HC595 to high, but in order to make the LEDs come on, the Arduino data pins corresponding to the horizontal planes must be set low.  If a different pattern is required for each plane, then some kind of simple ‘scanning’ is required as illustrated below.



따라서 hc595value 변수의 16 비트는 두 개의 8 비트 chunk로 직렬 포트를 통해 shift register로 전송 되며 이것은 latch pin을 통해 적절한 신호로 전송됩니다. 이것은 74HC595의 출력을 high로 설정하지만 LED를 켜기 위해 수평면에 해당하는 Arduino 데이터 핀을 low로 설정 해야합니다. 각 평면에 다른 패턴이 필요한 경우 아래에 설명 된 것처럼 일종의 간단한 '스캐닝'이 필요합니다.



int LED_Plane[] = {LED_Pin16, LED_Pin17, LED_Pin18, LED_Pin19};

/*
  Inputs: Array of 4 integers - one for each plane
*/
void display (unsigned int *pPattern)
{
  int i;
  for (i=0; i<4; i++)
  {
    int j;
    for (j=0; j<1000; j++)
    {
      // Slow this down so that there is time for the LEDS to light
      // Experimentation shows that 200+ gives brighter LEDs
      // NB: Do it this way so an empty loop isn't optimised out
      if (j==0)
      {
        digitalWrite(LED_Plane[0], HIGH);
        digitalWrite(LED_Plane[1], HIGH);
        digitalWrite(LED_Plane[2], HIGH);
        digitalWrite(LED_Plane[3], HIGH);
        write_74HC595 (pPattern[i]);
        digitalWrite(LED_Plane[i], LOW);
      }
    }
  }
}


I guess the only thing to really note here is that without the loop involving j then the ‘scanning’ was happening too fast to allow the LEDs to have any significant brightness at all.  I initially had a simple for (j=0; j<1000; j++) {}; statement at the end, but this seemed to be optimised out – at least it didn’t seem to have the delay effect I wanted, so instead I made the code only act on one pass through the loop.


여기서 정말로 주목할 것은, j를 포함하는 루프가 없으면 '스캐닝'이 너무 빠르게 진행 되어 LED가 충분히 밝게 되지 않는 다는 겁니다. 나는 처음에는  간단한 for 문을 (j = 0; j <1000; j ++) {}; 를 끝에 사용했습니다.  이것이 최적화 된 것처럼 보였지만 내가 원한 delay 효과를 보여주지는 못했습니다. 그래서 그렇게 하는 대신에 loop를 통과하는 것을 한번만 실행되도록 코딩했습니다. 



So, with these basics, it is now possible to get a 64 bit pattern, in the form of four 16 bit values, each representing one plane of 16 LEDs, onto the cube.


이렇게 함으로서 64 bit pattern이 가능해 졌습니다. 4개의 16 비트 값 형태로 각각이 큐브의 16 LEDs 의 한 평면을 나타내게 됩니다.



I have the full demo code file below – it isn’t massively pretty, and its not cpp (sorry – I’ve always been more of a C person I’m afraid, and my C is a little rusty), but it works for me.  Your proverbial mileage, as they say, may vary.


아래에 전체 코드가 있습니다. 코드가 깔끔하지 않고 cpp 로 돼 있지 않습니다. (나는 C 언어에 대해 그렇게 능숙하지가 못해서요.) 아무튼 이 소스코드는 잘 작동합니다. 



Kevin




#include <Arduino.h>

int HC595_clockPin=0;   // SH_CP of 74HC595 
int HC595_latchPin=1;   // ST_CP of 74HC595 
int HC595_dataPin=3;    // DS of 74HC595 
int HC595_enablePin=2;  // Not OE of 74HC595
int LED_Pin16= 4;
int LED_Pin17= 5;
int LED_Pin18= 6;
int LED_Pin19= 7;
int LED_Plane[] = {LED_Pin16, LED_Pin17, LED_Pin18, LED_Pin19};

// Each line (8 bytes) is an entire cube, with two consecutive bytes per plane of LEDS,
// and 16 LEDS per plane. LEDs are encoded in the following order:
//    Lowest plane byte 1, lowest plane byte 2, second lowerst plane 1, then 2,
//    second from top plane 1, then 2, highest plane 1, highest plane 2.
//
//    Each plane is encoded looking at the Arduino oriented with the USB/power
//    designated by 'south' by started 'north west' as follows:
//        D0    D1    D2    D3
//        D4    D5    D6    D7
//        D8    D9    D10   D11
//        D12   D13   D14   D15
//
//        D16   D17   D18   D19
//          (USB)      (Power)
//    With D16 being the lowest plane, through to D19 being the highest plane
//    Of course, if you wire the planes up differently, that is up to you!
//
//    Each two bytes of the pattern are therefore:
//        B00000000, B00000000 -> D0-7, D8-15
//    with D0 = msb of the first value, D7 being the lsb of the first value,
//    and  D8 = msb of the second value, D15 being the lsb of the second value.
//
//    So the entire pattern is:
//    B10010000,B00001001,B00000000,B00000000,B00000000,B00000000,B10010000,B00001001,
//     |      |  |     ||                                          |      |  |     ||
//     |      |  |     |\ D15 bottom plane                         |      |  |     |\ D15 top plane
//     |      |  |     \ D14 bottom plane                          |      |  |     \ D14 top plane
//     |      |  \ D8 bottom plane                                 |      |  \ D8 top plane
//     |      \ D7 bottom plane                                    |      \ D7 top plane
//     \ D0 bottom plane                                           \ D0 top plane
//
// Comment following in or out to switch patterns in or out
#define SWAP   1
#define SNAKE  1
#define BURST  1
#define SPIRAL 1
#define ALT    1
unsigned char pattern[] = {
#ifdef SWAP
  B10010000,B00001001,B00000000,B00000000,B00000000,B00000000,B10010000,B00001001,
  B00000000,B00000000,B10010000,B00001001,B10010000,B00001001,B00000000,B00000000,
  B00000000,B00000000,B01100000,B00000110,B01100000,B00000110,B00000000,B00000000,
  B01100000,B00000110,B00000000,B00000000,B00000000,B00000000,B01100000,B00000110,
  B00001001,B10010000,B00000000,B00000000,B00000000,B00000000,B00001001,B10010000,
  B00000000,B00000000,B00001001,B10010000,B00001001,B10010000,B00000000,B00000000,
  B00000000,B00000000,B00000110,B01100000,B00000110,B01100000,B00000000,B00000000,
  B00000110,B01100000,B00000000,B00000000,B00000000,B00000000,B00000110,B01100000,
#endif
#ifdef SNAKE
  B11001100,B00000000,B11001100,B00000000,B00000000,B00000000,B00000000,B00000000,
  B00000000,B00000000,B11001100,B00000000,B11001100,B00000000,B00000000,B00000000,
  B00000000,B00000000,B00000000,B00000000,B11001100,B00000000,B11001100,B00000000,
  B00000000,B00000000,B00000000,B00000000,B00001100,B11000000,B00001100,B11000000,
  B00000000,B00000000,B00000000,B00000000,B00000000,B11001100,B00000000,B11001100,
  B00000000,B00000000,B00000000,B00000000,B00000000,B01100110,B00000000,B01100110,
  B00000000,B00000000,B00000000,B00000000,B00000000,B00110011,B00000000,B00110011,
  B00000000,B00000000,B00000000,B00110011,B00000000,B00110011,B00000000,B00000000,
  B00000000,B00110011,B00000000,B00110011,B00000000,B00000000,B00000000,B00000000,
  B00000011,B00110000,B00000011,B00110000,B00000000,B00000000,B00000000,B00000000,
  B00110011,B00000000,B00110011,B00000000,B00000000,B00000000,B00000000,B00000000,
  B01100110,B00000000,B01100110,B00000000,B00000000,B00000000,B00000000,B00000000,
#endif
#ifdef BURST
  B00000000,B00000000,B00000110,B01100000,B00000110,B01100000,B00000000,B00000000,
  B00000110,B01100000,B01101001,B10010110,B01101001,B10010110,B00000110,B01100000,
  B01101001,B10010110,B10010000,B00001001,B10010000,B00001001,B01101001,B10010110,
  B10010000,B00001001,B00000000,B00000000,B00000000,B00000000,B10010000,B00001001,
  B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,
#endif
#ifdef SPIRAL
  B11001100,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,
  B01100110,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,
  B00110011,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,
  B00000011,B00110000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,
  B00000000,B00110011,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,
  B00000000,B01100110,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,
  B00000000,B11001100,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,
  B00001100,B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,
  B11001100,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,
  B00000000,B00000000,B11001100,B00000000,B00000000,B00000000,B00000000,B00000000,
  B00000000,B00000000,B01100110,B00000000,B00000000,B00000000,B00000000,B00000000,
  B00000000,B00000000,B00110011,B00000000,B00000000,B00000000,B00000000,B00000000,
  B00000000,B00000000,B00000011,B00110000,B00000000,B00000000,B00000000,B00000000,
  B00000000,B00000000,B00000000,B00110011,B00000000,B00000000,B00000000,B00000000,
  B00000000,B00000000,B00000000,B01100110,B00000000,B00000000,B00000000,B00000000,
  B00000000,B00000000,B00000000,B11001100,B00000000,B00000000,B00000000,B00000000,
  B00000000,B00000000,B00001100,B11000000,B00000000,B00000000,B00000000,B00000000,
  B00000000,B00000000,B11001100,B00000000,B00000000,B00000000,B00000000,B00000000,
  B00000000,B00000000,B00000000,B00000000,B11001100,B00000000,B00000000,B00000000,
  B00000000,B00000000,B00000000,B00000000,B01100110,B00000000,B00000000,B00000000,
  B00000000,B00000000,B00000000,B00000000,B00110011,B00000000,B00000000,B00000000,
  B00000000,B00000000,B00000000,B00000000,B00000011,B00110000,B00000000,B00000000,
  B00000000,B00000000,B00000000,B00000000,B00000000,B00110011,B00000000,B00000000,
  B00000000,B00000000,B00000000,B00000000,B00000000,B01100110,B00000000,B00000000,
  B00000000,B00000000,B00000000,B00000000,B00000000,B11001100,B00000000,B00000000,
  B00000000,B00000000,B00000000,B00000000,B00001100,B11000000,B00000000,B00000000,
  B00000000,B00000000,B00000000,B00000000,B11001100,B00000000,B00000000,B00000000,
  B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B11001100,B00000000,
  B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B01100110,B00000000,
  B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00110011,B00000000,
  B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,B00110000,
  B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00110011,
  B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B01100110,
  B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B11001100,
  B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00001100,B11000000,
  B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B11001100,B00000000,
#endif
#ifdef ALT
  B11111001,B10011111,B10010000,B00001001,B10010000,B00001001,B11111001,B10011111,
  B00000110,B01100000,B01101001,B10010110,B01101001,B10010110,B00000110,B01100000,
  B00000000,B00000000,B00000110,B01100000,B00000110,B01100000,B00000000,B00000000,
  B00000110,B01100000,B01101001,B10010110,B01101001,B10010110,B00000110,B01100000,
#endif
};
int patternNumber=0;
int numPatterns=sizeof(pattern)/8;
int tickCount=0;
int tickCountMax=50;      // How many times to loop before changing the pattern
unsigned int currentPattern[4];

void setup() {
  // put your setup code here, to run once:
  pinMode( HC595_latchPin,  OUTPUT );
  pinMode( HC595_clockPin,  OUTPUT );
  pinMode( HC595_dataPin,   OUTPUT );
  pinMode( HC595_enablePin, OUTPUT );
  
  pinMode( LED_Pin16, OUTPUT );
  pinMode( LED_Pin17, OUTPUT );
  pinMode( LED_Pin18, OUTPUT );
  pinMode( LED_Pin19, OUTPUT );
  
  digitalWrite(LED_Pin16,HIGH);
  digitalWrite(LED_Pin17,HIGH);
  digitalWrite(LED_Pin18,HIGH);
  digitalWrite(LED_Pin19,HIGH);
//  digitalWrite(HC595_enablePin, LOW);  // Enable Not OE (negative logic)

  patternNumber=0;
  tickCount = tickCountMax;
}

/*
  Protocol for sending the data to the hc595 is as follows:
   (see: http://www.arduino.cc/en/Tutorial/ShiftOut)
   
   "when the clock pin goes from low to high, the shift register
    reads the state of the data pin ... when the latch pin goes
    from low to high the sent data gets moved from the shift
    registers ... to the output pins"
   
   As we have two HC595s chained together, we use a 16 bit input value
*/
void write_74HC595 (unsigned int hc595value) { 
   digitalWrite(HC595_latchPin, LOW);   // ensures LEDs don't light whilst changing values
//   digitalWrite(HC595_enablePin, HIGH); // OE is negative logic
   
   // Shift each 8 bit value in sequence - the two chained HC595s automatically grab
   // the right bits - the first 8 to the first chip, second 8 to the second chip
   shiftOut(HC595_dataPin, HC595_clockPin, LSBFIRST, hc595value);  
   shiftOut(HC595_dataPin, HC595_clockPin, LSBFIRST, (hc595value >> 8));
   
   digitalWrite(HC595_latchPin, HIGH);  // data transferred from shift register to outputs when latch goes LOW->HIGH
//   digitalWrite(HC595_enablePin, LOW);  // re-enable (negative logic again)
}

/*
  Inputs: Array of 4 integers - one for each plane
*/
void display (unsigned int *pPattern)
{
  int i;
  for (i=0; i<4; i++)
  {
    int j;
    for (j=0; j<1000; j++)
    {
      // Slow this down so that there is time for the LEDS to light
      // Experimentation shows that 200+ gives brighter LEDs
      // NB: Do it this way so an empty loop isn't optimised out
      if (j==0)
      {
        digitalWrite(LED_Plane[0], HIGH);
        digitalWrite(LED_Plane[1], HIGH);
        digitalWrite(LED_Plane[2], HIGH);
        digitalWrite(LED_Plane[3], HIGH);
        write_74HC595 (pPattern[i]);
        digitalWrite(LED_Plane[i], LOW);
      }
    }
  }
}

void displayPattern ()
{
  int i;
  // only update it every tick otherwise just display as is
  tickCount--;
  if (tickCount <= 0)
  {
    tickCount = tickCountMax;
    for (i=0; i<4; i++)
    {
      currentPattern[i] = pattern[i*2 + patternNumber*8] * 256 + pattern[i*2 + 1 + patternNumber*8];
    }
    patternNumber++;
    if (patternNumber >= numPatterns)
    {
      patternNumber = 0;
    }
  }
  display(&currentPattern[0]);
}

void loop() {
  // put your main code here, to run repeatedly:
  displayPattern();
}



저작자 표시 비영리 동일 조건 변경 허락
신고


The Hamcrest Tutorial



Introduction

Hamcrest is a framework for writing matcher objects allowing 'match' rules to be defined declaratively. There are a number of situations where matchers are invaluble, such as UI validation, or data filtering, but it is in the area of writing flexible tests that matchers are most commonly used. This tutorial shows you how to use Hamcrest for unit testing.


Hamcrest는 'match'rule을 선언적으로 정의 해 matcher objects를 작성하기위한 framework입니다. UI 유효성 UI validation 또는 데이터 필터링과 같이 matchers가 사용할 수 없는 상황도 많이 있지만 matcher가 가장 일반적으로 사용되는 곳은 flexible tests를 작성하는 영역에 있습니다. 이 tutorial에서는 unit testing를 위해 Hamcrest를 사용하는 방법을 보여줍니다.


When writing tests it is sometimes difficult to get the balance right between overspecifying the test (and making it brittle to changes), and not specifying enough (making the test less valuable since it continues to pass even when the thing being tested is broken). Having a tool that allows you to pick out precisely the aspect under test and describe the values it should have, to a controlled level of precision, helps greatly in writing tests that are "just right". Such tests fail when the behaviour of the aspect under test deviates from the expected behaviour, yet continue to pass when minor, unrelated changes to the behaviour are made.


테스트를 작성할 때 테스트를 지나치게 자세하게 지정하는 것 (그리고 수정이 어렵게 하는 것)과 충분한 테스트를 하지 않는 것 사이의 균형을 잡기가 어렵기 때문에 (이럴 경우 테스트 대상에 문제가 생긴 경우에도 테스트가 pass 될 수 있어 해당 테스트가 유효하지 않게 됩니다.) 테스트 할 aspect를 정확하게 선택할 수 있도록 하고, 가져야 할 값을 describe 해서 정밀하게 제여할 수 있도록 하는 도구를 사용하면 "just right" 테스트를 작성하는 데 크게 도움이됩니다. 이러한 테스트는 테스트중인 aspect의 동작이 예상되는 벗어나는 경우 fail 하고 , minor 한 변화나 테스트 범위에서 벗어난 변경이 있는 경우 pass 해야 합니다.



My first Hamcrest test

We'll start by writing a very simple JUnit 3 test, but instead of using JUnit's assertEquals methods, we use Hamcrest's assertThatconstruct and the standard set of matchers, both of which we statically import:


아래 간단한 JUnit 3 test를 작성할 겁니다. JUnit의 assertEquals methods를 사용하는 대신에 Hamcrest의 assertThat construct와 matchers의 표준 세트를 사용할 겁니다. 이 둘은 정적으로 import 합니다.



``` import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*;


import junit.framework.TestCase;


public class BiscuitTest extends TestCase { public void testEquals() { Biscuit theBiscuit = new Biscuit("Ginger"); Biscuit myBiscuit = new Biscuit("Ginger"); assertThat(theBiscuit, equalTo(myBiscuit)); } } ```



The assertThat method is a stylized sentence for making a test assertion. In this example, the subject of the assertion is the object biscuit that is the first method parameter. The second method parameter is a matcher for Biscuit objects, here a matcher that checks one object is equal to another using the Object equals method. The test passes since the Biscuit class defines an equals method.


assertThat method는 test assertion을 만들기 위한 양식화 된 문장입니다. 이 예에서는 assertion의 subject는 첫 번째 method 매개 변수 인 object biscuit입니다. 두 번째 method 매개 변수는 Biscuit objects에 대한 matcher입니다. 여기에서 한 object를 검사하는 matcher는 Object equals method를 사용하는것과 같습니다. 이 테스트는 Biscuit 클래스가 equals method를 정의하기 때문에 pass 하게 됩니다.



If you have more than one assertion in your test you can include an identifier for the tested value in the assertion:


하나 이상의 assertion이 있는 경우 테스트 된 값에 대한 identifier를 assertion에 포함 할 수 있습니다.


assertThat("chocolate chips", theBiscuit.getChocolateChipCount(), equalTo(10)); assertThat("hazelnuts", theBiscuit.getHazelnutCount(), equalTo(3));



Other test frameworks



Hamcrest has been designed from the outset to integrate with different unit testing frameworks. For example, Hamcrest can be used with JUnit 3 and 4 and TestNG. (For details have a look at the examples that come with the full Hamcrest distribution.) It is easy enough to migrate to using Hamcrest-style assertions in an existing test suite, since other assertion styles can co-exist with Hamcrest's.


Hamcrest는 처음부터 다른 unit testing framework와 통합되도록 설계되었습니다. 예를 들어, Hamcrest는 JUnit 3과 4 및 TestNG와 함께 사용할 수 있습니다. (자세한 내용은 전체 Hamcrest distribution과 함께 제공되는 예제를 참조하십시오.) 다른 assertion 스타일이 Hamcrest와 같이 사용될 수 있기 때문에 기존 test suite에서 Hamcrest-style assertions를 사용하는 것으로 마이그레이션하는 것은 쉽습니다.


Hamcrest can also be used with mock objects frameworks by using adaptors to bridge from the mock objects framework's concept of a matcher to a Hamcrest matcher. For example, JMock 1's constraints are Hamcrest's matchers. Hamcrest provides a JMock 1 adaptor to allow you to use Hamcrest matchers in your JMock 1 tests. JMock 2 doesn't need such an adaptor layer since it is designed to use Hamcrest as its matching library. Hamcrest also provides adaptors for EasyMock 2. Again, see the Hamcrest examples for more details.


Hamcrest는 또한 mock objects framework와 같이 사용 될 수 있습니다. 그러려면 mock objects framework의 matcher와 Hamcrest의 matcher 에 대한 concept을 연결해 주도록 adaptors를 사용하면 됩니다. 예를 들어, JMock 1의 constraints는 Hamcrest의 matchers입니다. Hamcrest는 JMock 1 테스트에서 Hamcrest matchers를 사용할 수 있도록 JMock 1 어댑터를 제공합니다. JMock 2는 Hamcrest를 매칭 라이브러리로 사용하기 때문에 그러한 adaptor layer가 필요하지 않습니다. Hamcrest는 EasyMock 2 용 어댑터도 제공합니다. 자세한 내용은 Hamcrest 예제를 참조하십시오.



A tour of common matchers



Hamcrest comes with a library of useful matchers. Here are some of the most important ones.


Hamcrest는 유용한 matchers 라이브러리를 제공합니다. 그 중에 중요한 것들 입니다.



    Core
    • anything - always matches, useful if you don't care what the object under test is
    • describedAs - decorator to adding custom failure description
    • is - decorator to improve readability - see "Sugar", below

  • Logical
    • allOf - matches if all matchers match, short circuits (like Java &&)
    • anyOf - matches if any matchers match, short circuits (like Java ||)
    • not - matches if the wrapped matcher doesn't match and vice versa

  • Object
    • equalTo - test object equality using Object.equals
    • hasToString - test Object.toString
    • instanceOfisCompatibleType - test type
    • notNullValuenullValue - test for null
    • sameInstance - test object identity

  • Beans
    • hasProperty - test JavaBeans properties

  • Collections
    • array - test an array's elements against an array of matchers
    • hasEntryhasKeyhasValue - test a map contains an entry, key or value
    • hasItemhasItems - test a collection contains elements
    • hasItemInArray - test an array contains an element

  • Number
    • closeTo - test floating point values are close to a given value
    • greaterThangreaterThanOrEqualTolessThanlessThanOrEqualTo - test ordering

  • Text
    • equalToIgnoringCase - test string equality ignoring case
    • equalToIgnoringWhiteSpace - test string equality ignoring differences in runs of whitespace
    • containsStringendsWithstartsWith - test string matching



Sugar


Hamcrest strives to make your tests as readable as possible. For example, the is matcher is a wrapper that doesn't add any extra behavior to the underlying matcher. The following assertions are all equivalent:


Hamcrest는 여러분이 최대한 readable한 테스트를 만들 수 있도록 노력합니다. 예를 들어, is matcher는 기본이되는 matcher에 추가의 동작을 추가하지 않는 wrapper 입니다. (어떤 동작을 하지는 않고 단지 가독성 -readable- 을 제공하기 위한 것).

아래 assertion 들은 다 똑 같습니다.



assertThat(theBiscuit, equalTo(myBiscuit)); assertThat(theBiscuit, is(equalTo(myBiscuit))); assertThat(theBiscuit, is(myBiscuit));


The last form is allowed since is(T value) is overloaded to return is(equalTo(value)).


마지막 form은 is(T value)가 is(equalTo (value))를 return하도록 overload 되어 있기 때문에 가능합니다.



Writing custom matchers



Hamcrest comes bundled with lots of useful matchers, but you'll probably find that you need to create your own from time to time to fit your testing needs. This commonly occurs when you find a fragment of code that tests the same set of properties over and over again (and in different tests), and you want to bundle the fragment into a single assertion. By writing your own matcher you'll eliminate code duplication and make your tests more readable!


Hamcrest는 많은 유용한 matchers와 함께 번들로 제공되지만, 테스트 요구에 맞추기 위해 수시로 자신 만의 템플릿을 만들어야 할 필요가있을 것입니다. 이것은 일반적으로  동일한 properties set을 반복적으로 테스트 하는 (다른 테스트 들에서도) code의 fragment를 발견 했을 때 그리고 이 fragment를 단일 assertion으로 묶으려는 경우에 해당 될 겁니다. 자신 만의 matcher를 작성함으로써 코드 중복을 제거하고 테스트의 가독성을 훨씬 높일 수 있습니다!



Let's write our own matcher for testing if a double value has the value NaN (not a number). This is the test we want to write:


double 값의 값이 NaN (숫자가 아님) 인 경우를 테스트하기 위해 자체 matcher를 작성해 보겠습니다. 아래 그 예제가 있습니다.



public void testSquareRootOfMinusOneIsNotANumber() { assertThat(Math.sqrt(-1), is(notANumber())); }


And here's the implementation:


``` package org.hamcrest.examples.tutorial;

import org.hamcrest.Description; import org.hamcrest.Factory; import org.hamcrest.Matcher; import org.hamcrest.TypeSafeMatcher;

public class IsNotANumber extends TypeSafeMatcher {

@Override public boolean matchesSafely(Double number) { return number.isNaN(); }

public void describeTo(Description description) { description.appendText("not a number"); }

@Factory public static Matcher notANumber() { return new IsNotANumber(); }

} ```



The assertThat method is a generic method which takes a Matcher parameterized by the type of the subject of the assertion. We are asserting things about Double values, so we know that we need a Matcher<Double>. For our Matcher implementation it is most convenient to subclass TypeSafeMatcher, which does the cast to a Double for us. We need only implement the matchesSafely method - which simply checks to see if the Double is NaN - and the describeTo method - which is used to produce a failure message when a test fails. Here's an example of how the failure message looks:


assertThat method는, assertion의 subject의 type에 의해 파라미터 화 된 Matcher를 취하는 generic method입니다. 우리는 Double 값에 대해 asserting하고 있으므로 Matcher <Double>이 필요하다는 것을 알고 있습니다. 이 Matcher를 구현하는데 있어 TypeSafeMatcher를 서브 클래스로 implement 하는 것이 가장 좋습니다. TypeSafeMatcher는 Double로 형변환을 하게 됩니다. matchesSafely method와 describeTo method만 implement 하면 됩니다. matchesSafely method는 단순히 Double이 NaN인지 확인하고 describeTo method 테스트가 fail 할 경우 오류 메시지를 생성하는 데 사용됩니다. 다음은 failure message가 표시되는 예입니다.



assertThat(1.0, is(notANumber()));


fails with the message


java.lang.AssertionError: Expected: is not a number got : <1.0>



The third method in our matcher is a convenience factory method. We statically import this method to use the matcher in our test:


우리의 matcher에서 세 번째 method는 편리한 factory method 입니다. test에서 matcher를 사용하기 위해 이 method를 정적(statically)으로 가져옵니다.


``` import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*;

import static org.hamcrest.examples.tutorial.IsNotANumber.notANumber;

import junit.framework.TestCase;

public class NumberTest extends TestCase {

public void testSquareRootOfMinusOneIsNotANumber() { assertThat(Math.sqrt(-1), is(notANumber())); } } ```



Even though the notANumber method creates a new matcher each time it is called, you should not assume this is the only usage pattern for your matcher. Therefore you should make sure your matcher is stateless, so a single instance can be reused between matches.


비록 notANumber method가 호출 될 때마다 new matcher를 생성하지만, 이것이 matcher의 유일한 사용 patter 이라고 예단 해서는 안됩니다. 여러분은 이 matcher가 stateless 임을 유념해야 합니다. single instance 가 matcher들 사이에서 재사용 될 수 있습니다.



Sugar generation



If you produce more than a few custom matchers it becomes annoying to have to import them all individually. It would be nice to be able to group them together in a single class, so they can be imported using a single static import much like the Hamcrest library matchers. Hamcrest helps out here by providing a way to do this by using a generator.


여러가지 custom matchers를 만들었다면 이들을 각각 import 하는 일이 성가실 겁니다. 하나의 클래스에서 이들을 그룹화 하면 좋겠죠. 그렇게 하면 Hamcrest 라이브러리 matchers와 같이 single static import를 사용하여 한꺼번에 import 할 수 있을 겁니다. Hamcrest는 generator를 사용하여 이를 수행 할 수있는 방법을 제공합니다.


First, create an XML configuration file listing all the Matcher classes that should be searched for factory methods annotated with the org.hamcrest.Factory annotation. For example:


먼저, 모든 Matcher classes을 리스팅 한 XML configuration file을 생성합니다. 이것은 org.hamcrest.Factory annotation과 함께 factory methods annotated를 하기 위해 검색 될 겁니다. 예 :


```

```


Second, run the org.hamcrest.generator.config.XmlConfigurator command-line tool that comes with Hamcrest. This tool takes the XML configuration file and generates a single Java class that includes all the factory methods specified by the XML file. Running it with no arguments will display a usage message. Here's the output for the example.


둘째, Hamcrest와 함께 제공되는 org.hamcrest.generator.config.XmlConfigurator command-line tool를 실행하십시오. 이 도구는 XML 구성 파일을 사용하여 XML 파일에 지정된 모든 팩토리 method를 포함하는 단일 Java 클래스를 생성합니다. 인수없이 실행하면 사용법 메시지가 표시됩니다. 이 예제의 결과는 다음과 같습니다.



``` // Generated source. package org.hamcrest.examples.tutorial;

public class Matchers {

public static org.hamcrest.Matcher is(T param1) { return org.hamcrest.core.Is.is(param1); }

public static org.hamcrest.Matcher is(java.lang.Class param1) { return org.hamcrest.core.Is.is(param1); }

public static org.hamcrest.Matcher is(org.hamcrest.Matcher param1) { return org.hamcrest.core.Is.is(param1); }

public static org.hamcrest.Matcher notANumber() { return org.hamcrest.examples.tutorial.IsNotANumber.notANumber(); }

} ```



Finally, we can update our test to use the new Matchers class.


마지막으로 new Matchers class를 사용하도록 아래처럼 업데이트 합니다.



``` import static org.hamcrest.MatcherAssert.assertThat;

import static org.hamcrest.examples.tutorial.Matchers.*;

import junit.framework.TestCase;

public class CustomSugarNumberTest extends TestCase {

public void testSquareRootOfMinusOneIsNotANumber() { assertThat(Math.sqrt(-1), is(notANumber())); } } ```



Notice we are now using the Hamcrest library is matcher imported from our own custom Matchers class.


Notice 우리는 custom Matchers class 에서 importe된 matcher 인 Hamcrest library를 사용하게 됩니다.



Where next?

See FurtherResources.

--Tom White

저작자 표시 비영리 동일 조건 변경 허락
신고


Asynchronous Testing with Protractor’s ControlFlow


Protractor is an end-to-end testing framework for AngularJS applications that uses a real browser, just as a real user would. It is built on top of NodeJS and WebDriverJS and taps into the internals of Angular to know when Angular is done processing and updating bindings.



Protractor는 real user would와 마찬가지로 실제 브라우저를 사용하는 AngularJS 응용 프로그램의 end-to-end testing framework입니다. NodeJS 및 WebDriverJS 위에 구축되며 Angular의 내부를 tap해서 Angular가 바인딩 처리 및 업데이트를 완료 한 시점을 알 수 있습니다.


The joy of Protractorand WebDriverJS is that we can write our tests in a synchronous style, and still have the added benefits of asynchronous code. 


Protractor와 WebDriverJS의 강점은 동기식 스타일로 테스트를 작성할 수 있으며 비동기 코드의 부가적인 이점을 여전히 가지고 있다는 것입니다.

We are currently using Protractor for testing a Rails and Angular application that we’re developing here in the Detroit office. We were faced with a problem: “How do we write our own functions which are asynchronous but appear in the same synchronous style that Protractor tests are written in?” This is especially handy for performing REST requests for seeding data into the test database using something like the rails Hangar gem. 


우리는 현재 디트로이트 사무실에서 개발중인 Rails 및 Angular 응용 프로그램을 테스트하기 위해 Protractor를 사용하고 있습니다. "비동기식이지만 Protractor로 작성된 동기식으로 보이는 함수는 어떻게 작성합니까"  이것은 rails Hangar gem 같은 것을 사용해서 테스트 데이터베이스에 데이터를 넣기 위한 REST requests를 수행 할 때 특히 유용합니다. 


The ControlFlow


This required diving into the internals of how Protractor and WebDriverJS handle asynchrony. WebDriverJS uses an object called theControlFlow, which coordinates the scheduling and execution of commands operating on a queue. 


Any time an asynchronous command is invoked, it’s put in the queue where it will wait for all previous commands to complete prior to execution. The ControlFlow allows us to write code like this:


Protractor와 WebDriverJS가 어떻게 비동기를 처리하는지에 대해 좀 더 깊이 들어가겠습니다. WebDriverJS는 theControlFlow라는 객체를 사용합니다. 이 객체는 queue에서 작동하는 명령의 일정과 실행을 조정합니다.


비동기 명령이 호출 될 때마다 queue에 저장되어 실행 되기 전 모든 이전 명령들이 완료 될 때까지 대기합니다. ControlFlow를 사용하면 다음과 같은 코드를 작성할 수 있습니다.


driver.get(“http://www.google.com”);
driver.findElement(webdriver.By.name('q')).sendKeys('webdriver');
driver.findElement(webdriver.By.name('btnG')).click();
driver.getTitle().then(function(title) {
  console.log(title);
});


That really performs in a synchronous manner such as this:

이것은 아래와 같이 동기화 방식으로 처리 됩니다.


driver.get(“http://www.google.com”).
    then(function() {
      return driver.findElement(webdriver.By.name('q'));
    }).
    then(function(q) {
      return q.sendKeys('webdriver');
    }).
    then(function() {
      return driver.findElement(webdriver.By.name('btnG'));
    }).
    then(function(btnG) {
      return btnG.click();
    }).
    then(function() {
      return driver.getTitle();
    }).
    then(function(title) {
      console.log(title);
    });


Behind the scenes of WebDriver, each call that interacts with the browser, such as get()findElement()sendKeys(), and click(), is being scheduled and pushed onto the WebDriver ControlFlow, allowing us to not have to worry about using .then() on the resulting promises (unless we specifically want the result returned by the call). 

WebDriver의 이면에서 get (), findElement (), sendKeys () 및 click ()과 같이 브라우저와 상호 작용하는 각 호출이 예약되고 WebDriver ControlFlow에 푸시되므로 resulting promises 에 대해 걱정할 필요가 없습니다 (호출에 의해 반환 된 결과가 특별히 필요하지 않는 한)


Using the WebDriverJS Promises



The ControlFlow queues functions based on promises. The following code exhibits how to take a callback based function and wrap it into WebDriver’s Promise API. We will be using the Restler NodeJS library.


ControlFlow 대기열 기능은 promises를 기반으로합니다. 아래 코드는 callback 기반 함수를 WebDriver의 Promise API로 래핑하는 방법을 보여줍니다. 우리는 Restler NodeJS 라이브러리를 사용할 것입니다.

To create a WebDriver/Protractor deferred using their promise API:

promise API를 사용하여 지연된 WebDriver / Protractor를 만들려면 :


deferred = protractor.promise.defer()


Then fullfill or reject the promise based on Restler’s events and return the deferred promise:


restler.postJson(url, requestData, options).once('success', function() {
  return deferred.fulfill();
}).once('error', function() {
  return deferred.reject();
}).once('fail', function() {
  return deferred.reject();
});
 
deferred.promise;


Pushing the Promise Onto the ControlFlow



To solve our problem of invoking a synchronous REST request, we have to interact with WebDriver’s ControlFlow. 

To get the instance of the ControlFlow that is shared with protractor:


synchronous REST request를 invoking하는 문제를 해결하려면 WebDriver의 ControlFlow와 상호 작용해야합니다.

Protractor와 공유되는 ControlFlow의 인스턴스를 얻으려면 :


var flow = browser.controlFlow()


Then we can use the ControlFlow’s execute() function, assuming we created a based on the above code that wraps restler’s callbacks and returns a WebDriverJS promise:


그런 다음 Restler의 콜백을 래핑하고 WebDriverJS 약속을 반환하는 위 코드를 기반으로 ControlFlow의 execute () 함수를 사용할 수 있다고 가정합니다.


flow.execute(restFunction)


Chaining Promises and Getting Results



The good news is that ControlFlow’s execute() function returns a new promise that will be fulfilled when our original promise is executed by the scheduler. We can use use the all() function, which returns a new promise once all of the control flow’s promises are fulfilled:

좋은 소식은 ControlFlow의 execute () 함수가 새 promise를 반환한다는 겁니다. 이렇게 함으로서 원래 약속이 스케줄러에 의해 실행될 때 수행 될 이 조건이 충족되게 됩니다. 모든 control flow의 promises가 충족 됐을 때 new promise 가 반환되는 all () 함수를 사용할 수 있습니다.


var allPromise = protractor.promise.all(flow.execute(restFunction1), flow.execute(restFunction2))



When allPromise is fulfilled, it will return an array of the results of all the promises passed to all() as arguments. 

allPromise가 수행되면 all ()에 전달 된 모든 promises의 결과 배열을 인수로 반환합니다.


Ideally the implementation of your helper functions would abstract the intermediary promises that are being passed to the ControlFlow and purely operate based upon the promises returned from the ControlFlow’s execute function.

이상적으로 helper 함수의 구현은 ControlFlow로 전달되는 intermediary promises을 abstract화하고 ControlFlow의 실행 함수에서 반환 된 promises를 기반으로 작동합니다.


저작자 표시 비영리 동일 조건 변경 허락
신고


Simple version of LED Light stand base for 3D crystal laser cube



I have Taj Mahal 3D crystal laser Cube.

You can get it from ebay also.





I found there are many stand bases for these kind of 3D crystal cube and it makes gorgeous view of it. like below.



So I've decided to develop it using Arduino.


The result is this.





This is the Source code.


/*

  For LED Light stand for 3D Crystal laser cube


  version : 0.4


  created 03 May 2017


  by Douglas Changsoo Park

*/


// Define Pins

#define RED1 3

#define GREEN1 4

#define BLUE1 5

#define RED2 6

#define GREEN2 7

#define BLUE2 8

#define delayTime 100


// define variables

int redValue1;

int greenValue1;

int blueValue1;

int redValue2;

int greenValue2;

int blueValue2;


void setup() {

  pinMode(RED1, OUTPUT);

  pinMode(GREEN1, OUTPUT);

  pinMode(BLUE1, OUTPUT);

  digitalWrite(RED1, HIGH);

  digitalWrite(GREEN1, HIGH);

  digitalWrite(BLUE1, HIGH);


  pinMode(RED2, OUTPUT);

  pinMode(GREEN2, OUTPUT);

  pinMode(BLUE2, OUTPUT);

  digitalWrite(RED2, HIGH);

  digitalWrite(GREEN2, HIGH);

  digitalWrite(BLUE2, HIGH);


  redValue1 = random(1, 255);

  greenValue1  = random(1, 255);

  blueValue1  = random(1, 255);

  redValue2 = random(1, 255);

  greenValue2  = random(1, 255);

  blueValue2  = random(1, 255);

}


void loop() {

  LEDLights(redValue1, greenValue1, blueValue1, redValue2, greenValue2, blueValue2);

  delay(delayTime * 4);

}


void LEDLights(int red1, int green1, int blue1, int red2, int green2, int blue2) {


  redValue1 = red1;

  greenValue1 = green1;

  blueValue1 = blue1;

  redValue2 = red2;

  greenValue2 = green2;

  blueValue2 = blue2;


  int redResult1 = randomValue(redValue1);

  int greenResult1 = randomValue(greenValue1);

  int blueResult1 = randomValue(blueValue1);


  int redResult2 = randomValue(redValue2);

  int greenResult2 = randomValue(greenValue2);

  int blueResult2 = randomValue(blueValue2);


  for (int i = 0; i < 25; i += 1) {

    analogWrite(RED1, redValue1 + redResult1);

    analogWrite(GREEN1, greenValue1 + greenResult1);

    analogWrite(BLUE1, blueValue1 + blueResult1);

    analogWrite(RED2, redValue2 + redResult2);

    analogWrite(GREEN2, greenValue2 + greenResult2);

    analogWrite(BLUE2, blueValue2 + blueResult2);


    redValue1 = redValue1 + redResult1;

    greenValue1 = greenValue1 + greenResult1;

    blueValue1 = blueValue1 + blueResult1;

    redValue2 = redValue2 + redResult2;

    greenValue2 = greenValue2 + greenResult2;

    blueValue2 = blueValue2 + blueResult2;


    delay(delayTime);

  }

}


int randomValue(int value) {

  int result;

  int minN;

  int maxN;


  int interval = random(1, 5);


  if (interval == 1) {

    minN = 26;

    maxN = 229;

  } else if (interval == 2) {

    minN = 51;

    maxN = 204;

  } else if (interval == 3) {

    minN = 76;

    maxN = 179;

  } else if (interval == 4) {

    minN = 101;

    maxN = 154;

  } else {

    minN = 126;

    maxN = 129;

  }


  if (value < minN) {

    result = interval;

  } else if (value > maxN) {

    result = -interval;

  } else {

    int randomVal = random(0, 1);

    if (randomVal == 0) {

      result = interval;

    } else {

      result = -interval;

    }

  }


  return result;

}




I wanted to make a combination and change of a more varied and softer color using random() in randomValue() function.


LEDLights() function will turn on and change the LED Light with the return value of the randomValue() function.


The loop() function will call the LED LIghts() function repeatedly every given time.


The components will be configured as below.





I've used Arduino Nano, 12V battery pack with 8 AAA batteries, 1 car charger adapter, small bread board and 2 RGB LEDs.


all parts are what I already have. 


It will cost about $ 15 for a new purchase.



Link to my project in hackster.


https://www.hackster.io/solkit/portable-led-light-stand-for-3d-crystal-laser-cube-5d8bd1







저작자 표시 비영리 동일 조건 변경 허락
신고


I don't like you

Practice scripting for the project 'I like you'


Source Code


/*

  For I don't like you. (practice project for the project 'I like you')


  version : 0.1


  created 07 May 2017


  by Douglas Changsoo Park

*/


#include <Servo.h>

#include <NewPing.h>


#define TRIGGER_PIN  12  // Arduino pin tied to trigger pin on the ultrasonic sensor.

#define ECHO_PIN     11  // Arduino pin tied to echo pin on the ultrasonic sensor.

#define MAX_DISTANCE 200 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.


NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.

Servo myservo;//create servo object to control a servo


int distance;


void setup() {

  myservo.attach(9);//attachs the servo on pin 9 to servo object

  myservo.write(0);//back to 0 degrees 

  delay(1000);//wait for a second


  Serial.begin(9600); // Open serial monitor at 115200 baud to see ping results.

}


void loop() {

  delay(500);  // 

  unsigned int uS = sonar.ping(); // Send ping, get ping time in microseconds (uS).

  Serial.print("Ping: ");

  Serial.print(uS / US_ROUNDTRIP_CM); // Convert ping time to distance and print result (0 = outside set distance range, no ping echo)

  Serial.println("cm");

 

  distance = uS / US_ROUNDTRIP_CM;


  delay(500);

  // Servo motor moves when the distance is less than 5cm

  if (distance < 5 && distance != 0) {

    Serial.println("distance : ");

    Serial.println(distance); 

    myservo.write(90);//goes to 45 degrees 

    delay(500);

    myservo.write(-90);//goes to 45 degrees

    delay(500);

  }


}


==> Servo motor will move 90 degree and -90 degree when ultrasonic sensor detects object (person) in 5 cm.
Ultrasonic sonic sensor is going to be a pet's head so it looks like the pet is shaking his head because he doesn't like the person.

==> This is practice project of the project "I like you"
with the project, As you move, the pet will keep looking at you.
So the project name is "I like you" 

==> to do that I am planning to use 2 (or 3) ultrasonic sensor.

Anyway for the practice project "I don't like you", Arduino components should be configured as follows.



It will print the distance in 'cm' if it is run.




저작자 표시 비영리 동일 조건 변경 허락
신고







Testing and validating REST services in Java is harder than in dynamic languages such as Ruby and Groovy. REST Assured brings the simplicity of using these languages into the Java domain. For example if your HTTP server returns the following JSON at “http://localhost:8080/lotto/{id}”:


Ruby 및 Groovy와 같은 동적 언어보다 Java에서 REST 서비스를 테스트하고 유효성을 검사하는 것은 더 어렵습니다. REST Assured는 이러한 언어를 Java 도메인에서

 사용하는 간단한 방법을 제공합니다. 예를 들어 HTTP 서버가 "http : // localhost : 8080 / lotto / {id}"에 다음 JSON을 반환하는 경우 :


{
   "lotto":{
      "lottoId":5,
      "winning-numbers":[2,45,34,23,7,5,3],
      "winners":[
         {
            "winnerId":23,
            "numbers":[2,45,34,23,3,5]
         },
         {
            "winnerId":54,
            "numbers":[52,3,12,11,18,22]
         }
      ]
   }
}


You can easily use REST Assured to validate interesting things from the response:

REST Assured를 사용하여 response에서 원하는 것을 검증 할 수 있습니다.


@Test public void
lotto_resource_returns_200_with_expected_id_and_winners() {
    
    when().
            get("/lotto/{id}", 5).
    then().
            statusCode(200).
            body("lotto.lottoId", equalTo(5), 
                 "lotto.winners.winnerId", containsOnly(23, 54));

}


Looks easy enough? Why not give it a spin? See getting starting and usage guide.


정말 쉽죠? 널리 알려 주세요? getting starting 및 usage guide를 참조하세요.





Getting Started


Maven / Gradle Users


Add the following dependency to your pom.xml:


아래 dependency를 pom.xml에 추가하세요.


REST Assured

Includes JsonPath and XmlPath

Maven:

<dependency>
      <groupId>io.rest-assured</groupId>
      <artifactId>rest-assured</artifactId>
      <version>3.0.3</version>
      <scope>test</scope>
</dependency>

Gradle:

testCompile 'io.rest-assured:rest-assured:3.0.3'

Notes

  1. You should place rest-assured before the JUnit dependency declaration in your pom.xml / build.gradle in order to make sure that the correct version of Hamcrest is used.
  2. REST Assured includes JsonPath and XmlPath as transitive dependencies
Notes

1. Hamcrest의 올바른 버전이 사용되는지 확인하기 위해 pom.xml / build.gradle에서 JUnit dependency declaration 앞에 rest-assured를 넣어야 합니다.
2. REST Assured는 JsonPath 및 XmlPath를 transitive dependencies로 include합니다.

JsonPath


Standalone JsonPath (included if you depend on the rest-assured artifact). Makes it easy to parse JSON documents. Note that this JsonPath implementation uses Groovy's GPath syntax and is not to be confused with Kalle Stenflo's JsonPath implementation.

Standalone JsonPath (rest-assured artifact에 의존하는 경우 포함됨). 이렇게 함으로서 JSON 문서를 쉽게 파싱 할 수 있습니다. 이 JsonPath 구현은 Groovy의 GPath 구문을 사용하므로 Jayway의 다른 JsonPath 구현과 혼동하지 않아야합니다.


Maven:

<dependency>
      <groupId>io.rest-assured</groupId>
      <artifactId>json-path</artifactId>
      <version>3.0.3</version>
</dependency>

Gradle:

compile 'io.rest-assured:json-path:3.0.3'


XmlPath


Stand-alone XmlPath (included if you depend on the rest-assured artifact). Makes it easy to parse XML documents.

 Stand-alone XmlPath (rest-assured artifact에 의존하는 경우 포함됨). 이렇게 함으로서 XML 문서를 쉽게 파싱 할 수 있습니다.


Maven:

<dependency>
      <groupId>io.rest-assured</groupId>
      <artifactId>xml-path</artifactId>
      <version>3.0.3</version>
</dependency>

Gradle:

compile 'io.rest-assured:xml-path:3.0.3'


JSON Schema Validation


If you want to validate that a JSON response conforms to a Json Schema you can use the json-schema-validator module:

JSON 응답이 Json Schema를 따르는 지 확인하려면 json-schema-validator 모듈을 사용할 수 있습니다.


Maven:

<dependency>
      <groupId>io.rest-assured</groupId>
      <artifactId>json-schema-validator</artifactId>
      <version>3.0.3</version>
      <scope>test</scope>
</dependency>

Gradle:

testCompile 'io.rest-assured:json-schema-validator:3.0.3'


Refer to the documentation for more info.

자세한 내용은 설명서를 참조하십시오.


Spring Mock Mvc


If you're using Spring Mvc you can now unit test your controllers using the RestAssuredMockMvc API in the spring-mock-mvc module. For this to work you need to depend on the spring-mock-mvc module:

Spring Mvc를 사용하고 있다면 Spring Mock-mvc 모듈의 RestAssuredMockMvc API를 사용하여 controllers를 유닛 테스트 할 수 있습니다. 이 작업을 하기 위해서는 spring-mock-mvc 모듈에 의존해야합니다.


Maven:

<dependency>
      <groupId>io.rest-assured</groupId>
      <artifactId>spring-mock-mvc</artifactId>
      <version>3.0.3</version>
      <scope>test</scope>
</dependency>

Gradle:

testCompile 'io.rest-assured:spring-mock-mvc:3.0.3'


Scala Support


If you're using Scala you may leverage the scala-support module. For this to work you need to depend on the scala-support module:


Scala를 사용하는 경우 Scala 지원 모듈을 활용할 수 있습니다. 이 작업을 수행하려면 scala-support 모듈에 의존해야합니다.


SBT:

libraryDependencies += "io.rest-assured" % "scala-support" % "3.0.3"

Maven:

<dependency>
    <groupId>io.rest-assured</groupId>
    <artifactId>scala-support</artifactId>
    <version>3.0.3</version>
    <scope>test</scope>
</dependency>

Gradle:

testCompile 'io.rest-assured:scala-support:3.0.3'


Non-maven users


Download REST Assured and Json Schema Validator (optional). You can also download XmlPath and/or JsonPath separately if you don't need REST Assured. If you're using Spring Mvc then you can download the spring-mock-mvc module as well. If you're using Scala you may optionally download the scala-support module. Extract the distribution zip file and put the jar files in your class-path.


REST Assured 및 Json Schema Validator (선택 사항)를 다운로드하십시오. REST Assured가 필요하지 않은 경우 XmlPath 와 JsonPath를 별도로 다운로드 할 수도 있습니다. 당신이 Spring Mvc를 사용하고 있다면 당신은 spring-mock-mvc 모듈을 다운로드 할 수있습니다. Scala를 사용하는 경우 선택적으로 Scala 지원 모듈을 다운로드 할 수 있습니다. 배포 zip 파일의 압축을 풀고 jar 파일을 클래스 경로에 넣습니다.





Static imports


In order to use REST assured effectively it's recommended to statically import methods from the following classes:

REST assured를 효과적으로 사용하려면 다음 클래스에서 메소드를 정적으로 가져 오는 것이 좋습니다.


io.restassured.RestAssured.*
io.restassured.matcher.RestAssuredMatchers.*
org.hamcrest.Matchers.*


If you want to use Json Schema validation you should also statically import these methods:

Json Schema 유효성 검사를 사용하려면 다음 메소드를 정적으로 가져와야합니다.


io.restassured.module.jsv.JsonSchemaValidator.*


Refer to Json Schema Validation section for more info.

자세한 내용은 Json 스키마 유효성 검사 섹션을 참조하십시오.


If you're using Spring MVC you can use the spring-mock-mvc module to unit test your Spring Controllers using the Rest Assured DSL. To do this statically import the methods from RestAssuredMockMvc instead of importing the methods from io.rest-assured.RestAssured and io.rest-assured.matcher.RestAssuredMatchers:


Spring MVC를 사용한다면, Spring-mock-mvc 모듈을 사용하여 Rest Assured DSL을 사용하여 Spring Controllers를 테스트 할 수있다. 이렇게하려면 io.rest-assured.RestAssured 및 io.rest-assured.matcher.RestAssuredMatchers에서 메서드를 가져 오는 대신 RestAssuredMockMvc에서 메서드를 정적으로 가져옵니다.


io.restassured.module.mockmvc.RestAssuredMockMvc.*
io.restassured.matcher.RestAssuredMatchers.*


Version 2.x


If you need to depend on an older version replace groupId io.rest-assured with com.jayway.restassured.


이전 버전에 의존해야한다면 com.jayway.restassured로 groupId io.rest-assured를 교체하십시오.


Documentation


When you've successfully downloaded and configured REST Assured in your classpath please refer to the usage guide for examples.


클래스 패스에 REST Assured를 성공적으로 다운로드하고 구성한 경우 예제를 보려면 사용 설명서를 참조하십시오.






Usage Guide




Note that if you're using version 1.9.0 or earlier please refer to the legacy documentation.


버전 1.9.0 이전 버전을 사용하는 경우 기존 설명서를 참조하십시오.


REST Assured is a Java DSL for simplifying testing of REST based services built on top of HTTP Builder. It supports POST, GET, PUT, DELETE, OPTIONS, PATCH and HEAD requests and can be used to validate and verify the response of these requests.


REST Assured는 HTTP 빌더 위에 구축 된 REST 기반 서비스의 테스트를 단순화하기위한 Java DSL입니다. POST, GET, PUT, DELETE, OPTIONS, PATCH 및 HEAD 요청을 지원하며 이러한 요청의 응답을 확인하고 검증하는 데 사용할 수 있습니다.




Contents

  1. Static imports
  2. Examples
  3. JSON Example
  4. JSON Schema Validation
  5. XML Example
  6. Advanced
  7. XML
  8. JSON
  9. Additional Examples
  10. Note on floats and doubles
  11. Note on syntax (syntactic sugar)
  12. Getting Response Data
  13. Extracting values from the Response after validation
  14. JSON (using JsonPath)
  15. XML (using XmlPath)
  16. Single Path
  17. Headers, cookies, status etc
  18. Multi-value headers
  19. Multi-value cookies
  20. Detailed Cookies
  21. Specifying Request Data
  22. Invoking HTTP resources
  23. Parameters
  24. Multi-value Parameter
  25. No-value Parameter
  26. Path Parameters
  27. Cookies
  28. Headers
  29. Content-Type
  30. Request Body
  31. Verifying Response Data
  32. Response Body
  33. Cookies
  34. Status
  35. Headers
  36. Content-Type
  37. Full body/content matching
  38. Use the response to verify other parts of the response
  39. Measuring response time
  40. Authentication
  41. Basic
  42. Preemptive
  43. Challenged
  44. Digest
  45. Form
  46. CSRF
  47. OAuth
  48. OAuth1
  49. OAuth2
  50. Multi-part form data
  51. Object Mapping
  52. Serialization
  53. Content-Type based Serialization
  54. Create JSON from a HashMap
  55. Using an Explicit Serializer
  56. Deserialization
  57. Content-Type based Deserialization
  58. Custom Content-Type Deserialization
  59. Using an Explicit Deserializer
  60. Configuration
  61. Custom
  62. Parsers
  63. Custom
  64. Default
  65. Default Values
  66. Specification Re-use
  67. Filters
  68. Ordered Filters
  69. Response Builder
  70. Logging
  71. Request Logging
  72. Response Logging
  73. Log if validation fails
  74. Root Path
  75. Path Arguments
  76. Session Support
  77. Session Filter
  78. SSL
  79. SSL invalid hostname
  80. URL Encoding
  81. Proxy Configuration
  82. Static Proxy Configuration
  83. Request Specification Proxy Configuration
  84. Detailed configuration
  85. Encoder Config
  86. Decoder Config
  87. Session Config
  88. Redirect DSL
  89. Connection Config
  90. JSON Config
  91. HTTP Client Config
  92. SSL Config
  93. Param Config
  94. Spring Mock Mvc Module
  95. Bootstrapping RestAssuredMockMvc
  96. Asynchronous Requests
  97. Adding Request Post Processors
  98. Adding Result Handlers
  99. Using Result Matchers
  100. Interceptors
  101. Specifications
  102. Resetting RestAssuredMockMvc
  103. Spring MVC Authentication
    1. Using Spring Security Test
    2. Injecting a User
  104. Note on parameters
  105. Scala Support Module
  106. Kotlin
  107. More Info



저작자 표시 비영리 동일 조건 변경 허락
신고



README.md


Protractor-Perf


Just like Protractor is the end to end test case runner for AngularJS to check for functional regressions, this project is a way check for performance regressions while reusing the same test cases.


Protractor가 기능적 회귀 (functional regressions) 를 검사하는 end to end test case runner 인 것처럼,  이 프로젝트는 동일한 테스트 케이스를 재사용하면서 performance regressions를 확인하는 방법입니다.




Usage


Install protractor-perf using npm install -g protractor-perf.


npm install -g protractor-perf를 사용해 protractor-perf 를 설치하세요.


Protractor test cases are re-used to run scenarios where performance needs to be measured. Protractor-perf can be used just like protractor, just that the test-cases need to be instrumented to indicated when to start and stop measuring performance.


Protractor 테스트 케이스는 performance을 측정해야하는 시나리오를 실행하기 위해 재사용됩니다. Protractor-perf는 Protractor처럼 사용할 수 있습니다. performance를 측정하기 위해 시작점과 끝나는 지점을 테스트 케이스 내에 정해주고 난 후 측정할 수 있습니다 


Protractor is usually invoked using $ protractor conf.js. Use $ protractor-perf conf.js instead to start measuring performance.


Protractor는 일반적으로 $ protractor conf.js.를 사용하여 호출됩니다. $ protractor-perf conf.js를 사용하여 성능 측정을 시작하십시오.



The config file is the same configuration file used for protractor tests.


config 파일은 Protractor 테스트에 사용되는 것과 동일한 구성 파일입니다.



Note: If you run selenium using protractor's webdriver-manager, you would need to specify seleniumPort and selenium keys in the config file, to explicitly specify the port on which the selenium server will run. This port will also be picked up by protractor-perf. See ./test/conf.js as an example.


참고 : Protractor의 webdriver-manager를 사용하여 selenium을 실행하는 경우 seleniumPort와 selenium keys를 config 파일에 명시합니다. 이렇게 함으로서 셀레니엄 서버가 돌아갈 포트를 특정할 수 있습니다.  ./test/conf.js 의 예를 참조하십시오.


When the instrumented test cases are run using protractor, the code related to performance is a no-op. This way, adding instrumentation does not break your ability to run protractor to just test for functionality.


퍼포먼스 테스팅이 구현 된 테스트 케이스가 Protractor를 사용하여 실행될 때 성능과 관련된 코드는 작동하지 않습니다. 이런 방법으로 이 기능을 추가해도 Protractor를 작동시켜 functionalityㄹ으 테스트하는 기능은 영향을 받지 않습니다.




Instrumenting the test cases

The test case need to specify when to start and stop measuring performance metrics for a certain scenario. The following code is an example of a test case, with perf code snippets added.


테스트 케이스에 특정 시나리오에 대한 performance metrics 측정을 시작하고 중지 할 시기를 지정합니다. 다음 코드는 perf 코드 snippets이 추가 된 테스트 사례의 예입니다.


var PerfRunner = require('..');
describe('angularjs homepage todo list', function() {
	var perfRunner = new PerfRunner(protractor, browser);

	it('should add a todo', function() {
		browser.get('http://www.angularjs.org');
		perfRunner.start();

		element(by.model('todoList.todoText')).sendKeys('write a protractor test');
		element(by.css('[value="add"]')).click();

		perfRunner.stop();

		if (perfRunner.isEnabled) {
			expect(perfRunner.getStats('meanFrameTime')).toBeLessThan(60);
		};

		var todoList = element.all(by.repeater('todo in todoList.todos'));
		expect(todoList.count()).toEqual(3);
		expect(todoList.get(2).getText()).toEqual('write a protractor test');

	});
});


The four statements to note are

메모 할 4 가지 문구는 다음과 같습니다.


  1. Initialize the Perf monitor using new ProtractorPerf(protractor, browser)
  2. To start measuring the perf, use perf.start()
  3. Once the scenario that you would like to perf test completes, use perf.stop()
  4. Finally, use perf.getStats('statName') in expect statements to ensure that all the performance metrics are within the acceptable range.

The perf.isEnabled is needed to ensure that perf metrics are not tested when the test case is run using protractor directly.


1. new ProtractorPerf (Protractor, browser)를 사용하여 Perf 모니터를 초기화하십시오.

2. perf를 측정하려면 perf.start ()를 사용하십시오.

3. perf 테스트를 수행하려는 시나리오가 완료되면 perf.stop () 를 사용하십시오.

4. 마지막으로 expect 문에서 perf.getStats ( 'statName')를 사용하여 모든 performance metrics이 허용되는 범위 내에 있는지 확인하십시오.


perf.isEnabled는 Protractor를 사용하여 테스트 케이스를 직접 실행할 때 perf metrics을 테스트하지 않도록하기 위해 필요합니다.



Metrics measured


protractor-perf is based on browser-perfbrowser-perf measures the metrics that can be tested for regressions. Look at browser-perf's wiki page for more information about the project.


protractor-perf는 browser-perf를 기반으로합니다. browser-perf는 regressions 테스트 할 수있는 metrics을 측정합니다. 프로젝트에 대한 자세한 내용은 browser-perf의 wiki 페이지를 참조하십시오.




Grunt Integration


Invoke protractor-perf from a GruntFile as below


아래와 같이 GruntFile 에서 protractor-perf를 Invoke 시키세요.


module.exports = function(grunt) {
  var protractorperf = require('protractor-perf');
  grunt.registerTask('protractorperf', function() {
    var donerun = this.async();
    // Optional config Object that overwrites properties of conf.js.
    // Useful to set property values from grunt.option()
    var argv = {
      selenium: 'http://localhost:54321/wd/hub',
      seleniumPort: 54321
    };
    protractorperf.run('./merci-perf-conf.js', donerun, argv); // config file
  });
  grunt.registerTask('run', ['protractorperf']);
};



저작자 표시 비영리 동일 조건 변경 허락
신고

IT Nomad life for 17 years

2017.04.27 09:45 | Posted by 솔웅








IT Nomad life for 17 years






South Korea -> India -> Slovakia -> Netherlands -> USA



traveled five countries all over the world.



NJ (Little Ferry) -> RI (Smithfield) -> CA (San Diego) -> MN (Eden Prairie) -> IL (Chicago)



lived in 5 states in the USA.



Such a challenging life. :)





It's My Life




This ain't a song for the broken-hearted
No silent prayer for the faith-departed
I ain't gonna be just a face in the crowd
You're gonna hear my voice
When I shout it out loud

It's my life
It's now or never
I ain't gonna live forever
I just want to live while I'm alive
(It's my life)
My heart is like an open highway
Like Frankie said
I did it my way
I just want to live while I'm alive
It's my life

This is for the ones who stood their ground
It's for Tommy and Gina who never backed down
Tomorrow's getting harder, make no mistake
Luck ain't enough
You've got to make your own breaks

It's my life
And it's now or never
I ain't gonna live forever
I just want to live while I'm alive
(It's my life)
My heart is like an open highway
Like Frankie said
I did it my way
I just want to live while I'm alive
It's my life

You better stand tall when they're calling you out
Don't bend, don't break, baby, don't back down

It's my life
And it's now or never
I ain't gonna live forever
I just want to live while I'm alive
(It's my life)
My heart is like an open highway
Like Frankie said
I did it my way
I just want to live while I'm alive
(It's my life)




저작자 표시 비영리 동일 조건 변경 허락
신고




Using Hamcrest for testing - Tutorial





1. Purpose of the Hamcrest matcher framework


Hamcrest is a framework for software tests. Hamcrest allows checking for conditions in your code via existing matchers classes. It also allows you to define your custom matcher implementations.


Hamcrest는 소프트웨어 테스트를위한 framework입니다. Hamcrest는 기존 matchers 클래스를 통해 코드의 조건을 확인할 수 있습니다. 또한 사용자 정의 matcher implementations 을 정의 할 수 있습니다.


To use Hamcrest matchers in JUnit you use the assertThat statement followed by one or several matchers.


JUnit에서 Hamcrest matcher를 사용하려면 assertThat 문 뒤에 하나 또는 여러 개의 matchers를 사용합니다.


Hamcrest is typically viewed as a third generation matcher framework. The first generation used assert(logical statement) but such tests were not easily readable. The second generation introduced special methods for assertions, e.g., assertEquals(). This approach leads to lots of assert methods. Hamcrest uses assertThat method with a matcher expression to determine if the test was succesful. See Wiki on Hamcrest for more details.


Hamcrest는 일반적으로 3 세대 정규식 framework로 간주됩니다. 1 세대는 assert(logical statement)을 사용했지만 그러한 테스트는 쉽게 읽을 수 없었습니다. 2 세대에서는 assertEquals()와 같은 assertions을 위한 특수한 메소드가 도입되었습니다. 이 접근법은 많은 assert methods 를 필요로 합니다. Hamcrest는 assertThat 메서드를 사용하여 테스트가 성공적인지 여부를 확인하는 matcher expression을 사용합니다. 자세한 내용은 Hamcrest의 Wiki를 참조하십시오.




Hamcrest has the target to make tests as readable as possible. For example, the is method is a thin wrapper for equalTo(value).


Hamcrest는 최대한 가독성있는 test scripts를 가지는 것을 목표로 하고 있습니다. 예를 들어, is 메소드는 equalTo(value)에 대한 thin wrapper입니다.


import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.equalTo;

boolean a;
boolean b;

// all statements test the same
assertThat(a, equalTo(b));
assertThat(a, is(equalTo(b)));
assertThat(a, is(b));


The following snippets compare pure JUnit 4 assert statements with Hamcrest matchers.


다음 snippets은 순수 JUnit 4 assert statements와 Hamcrest matchers를 비교합니다.


// JUnit 4 for equals check
assertEquals(expected, actual);
// Hamcrest for equals check
assertThat(actual, is(equalTo(expected)));

// JUnit 4 for not equals check
assertNotEquals(expected, actual)
// Hamcrest for not equals check
assertThat(actual, is(not(equalTo(expected))));

It is also possible to chain matchers, via the anyOf of allOf method.


allOf 메소드의 anyOf를 통해 matcher를 연결할 수도 있습니다.


assertThat("test", anyOf(is("testing"), containsString("est")));

In general the Hamcrest error messages are also much easier to read.


일반적으로 Hamcrest 오류 메시지는 읽기가 훨씬 쉽습니다.


assertTrue(result instanceof String);
// error message:
java.lang.AssertionError
    at org.junit.Assert.fail(Assert.java:86)
    at org.junit.Assert.assertTrue(Assert.java:41)
    at org.junit.Assert.assertTrue(Assert.java:52)
// ...


assertEquals(String.class, result.getClass());
// error message:
java.lang.NullPointerException
    at com.vogella.hamcrest.HamcrestTest.test(HamcrestTest.java:30)
// ....


assertThat(result, instanceOf(String.class));
// error message:
java.lang.AssertionError:
Expected: an instance of java.lang.String
     but: null
    at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
    at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:8)
// ...


Using Hamcrest matchers also provides more type safety as these matchers use generics.


Hamcrest matchers를 사용하면 matcher가 generics를 사용하므로 더 많은 type safety을 제공합니다.





2. Using Hamcrest matchers


2.1. Defining a Hamcrest dependency for Gradle


To use Hamcrest matchers for a project based on the Gradle build system, add the following dependencies to it.

Gradle 빌드 시스템을 기반으로하는 프로젝트에 Hamcrest matchers를 사용하려면 다음 dependencies를 추가하십시오.


dependencies {
    // Unit testing dependencies
    testCompile 'junit:junit:4.12'
    // Set this dependency if you want to use Hamcrest matching
    testCompile 'org.hamcrest:hamcrest-library:1.3'
}


2.2. Defining a Hamcrest dependency for Maven


To use the library for a Maven based project, the following dependency to your pom file.


Maven 기반 프로젝트에 라이브러리를 사용하려면, pom 파일에 다음과 같은 dependencies를 부여하십시오.


<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>



2.3. Adding Hamcrest directly to the classpath in Eclipse



The JUnit distribution included in Eclipse only contain the core Hamcrest matcher. To use all available matchers, download the latest hamcrest-all-*.jar from https://code.google.com/p/hamcrest/downloads/list and add it to your projects classpath.


Eclipse에 포함 된 JUnit 배포판에는 core Hamcrest matcher 만 포함됩니다. 사용 가능한 모든 matcher를 사용하려면 https://code.google.com/p/hamcrest/downloads/list에서 최신 hamcrest-all - * .jar 파일을 다운로드하여 프로젝트 classpath에 추가하십시오.


If you get the following exception "java.lang.SecurityException: class "org.hamcrest.Matchers"'s signer information does not match signer information of other classes in the same package", ensure that the hamcrest jar is before the Junit library in the build path. You an configure the order in the project properties in the Eclipse IDE under Java Build Path on the Order and Export tab.


"java.lang.SecurityException : class"org.hamcrest.Matchers "의 서명자 정보가 같은 패키지의 다른 클래스의 서명자 정보와 일치하지 않는 경우"hamcrest jar가 Junit 라이브러리보다 앞에 있는지 확인하십시오. 빌드 경로. Eclipse IDE의 프로젝트 특성에서 순서 및 내보내기 탭의 Java 빌드 경로 아래에 순서를 구성하십시오.







3. Using Hamcrest


3.1. Example


The usage of Hamcrest matchers is demonstrates by the following code snippet.


Hamcrest matchers의 사용법은 다음 code snippet을 통해 보여줍니다.


assertThat(Long.valueOf(1), instanceOf(Integer.class));
// shortcut for instanceOf
assertThat(Long.valueOf(1), isA(Integer.class));


3.2. Static import


To make all matchers available in your file add an static import. This also makes it easier to find matchers through code completion.


파일에서 모든 matcher를 사용할 수 있게 하려면 static import를 추가하십시오. 이러면 code completion을 통해 matcher를 쉽게 찾을 수 있도록 해 주기도 합니다.


import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;



3.3. Hamcrest matchers for lists


The usage of the Hamcrest matchers for lists are demonstrated by the following example.


lists에 대한 Hamcrest matchers의 사용법은 다음 예제에서 보여 줍니다.


import org.junit.Test;

import java.util.Arrays;
import java.util.List;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
import static org.hamcrest.core.Every.everyItem;

public class HamcrestListMatcherExamples {
    @Test
    public void listShouldInitiallyBeEmpty() {
        List<Integer> list = Arrays.asList(5, 2, 4);

        assertThat(list, hasSize(3));

        // ensure the order is correct
        assertThat(list, contains(5, 2, 4));

        assertThat(list, containsInAnyOrder(2, 4, 5));

        assertThat(list, everyItem(greaterThan(1)));

    }
}
// Check that a list of objects has a property race and
// that the value is not ORC
assertThat(fellowship, everyItem(hasProperty("race", is(not((ORC))))));



3.4. Overview of Hamcrest mather



The following are the most important Hamcrest matchers:


다음은 가장 중요한 Hamcrest matchers들 입니다.


  • allOf - matches if all matchers match (short circuits)

  • anyOf - matches if any matchers match (short circuits)

  • not - matches if the wrapped matcher doesn’t match and vice

  • equalTo - test object equality using the equals method

  • is - decorator for equalTo to improve readability

  • hasToString - test Object.toString

  • instanceOfisCompatibleType - test type

  • notNullValuenullValue - test for null

  • sameInstance - test object identity

  • hasEntryhasKeyhasValue - test a map contains an entry, key or value

  • hasItemhasItems - test a collection contains elements

  • hasItemInArray - test an array contains an element

  • closeTo - test floating point values are close to a given value

  • greaterThangreaterThanOrEqualTolessThanlessThanOrEqualTo

  • equalToIgnoringCase - test string equality ignoring case

  • equalToIgnoringWhiteSpace - test string equality ignoring differences in runs of whitespace

  • containsStringendsWithstartsWith - test string matching


To see all matchers, use API reference.


모든 matchers를 보려면 API 참조를 사용하십시오.


4. Exercise - Writing a custom Hamcrest matcher using FeatureMatcher


4.1. Target



The target of this exercise is to write a custom matcher with Hamcrest.


이 exercise의 목표는 Hamcrest 에서 custom matcher를 작성하는 것입니다.



4.2. Create Hamcrest Matchers


Define a custom matcher for Hamcrest which provides the length matcher for a String. We want to use the class FeatureMatcher. With FeatureMatcher we can wrap an existing Matcher, decide which field of the given Object under test to match and provide a nice error message. The constructor of FeatureMatcher takes the following arguments in this order:


Hamcrest를위한 custom matcher를 정의하여 String에 대한 length matcher를 제공합니다. 우리는 FeatureMatcher 클래스를 사용하고자합니다. FeatureMatcher를 사용하면 기존 Matcher를 wrap하고 테스트 할 대상 객체의 필드를 결정하여 나은 오류 메시지를 제공 할 수 있습니다. FeatureMatcher의 생성자는 다음 순서로 인수를 취합니다.



  • The matcher we want to wrap

  • a description of the feature that we tested

  • a description of the possible mismatch


The only method we have to overwrite is featureValueOf(T actual) which returns the value which will get passed into the wrapped matches()/matchesSafely() method.


overwrite하는 유일한 방법은 wrapped matches () / matchesSafely () 메서드에 전달 될 값을 반환하는 featureValueOf (T actual)입니다.


public static Matcher<String> length(Matcher<? super Integer> matcher) {
    return new FeatureMatcher<String, Integer>(matcher, "a String of length that", "length") {
        @Override
        protected Integer featureValueOf(String actual) {
            return actual.length();
        }
    };
}


4.3. Validate



Use your custom matcher to check that "Gandalf" has a lenght of 8.


Gandalf의 길이가 8인지에 대해 여러분의 custom matcher 를 사용해서 확인해 보세요.


@Test
public void fellowShipOfTheRingShouldContainer7() {
        assertThat("Gandalf", length(is(8)));
}
public static  Matcher<String> length(Matcher<? super Integer> matcher) {
        return new FeatureMatcher<String, Integer>(matcher, "a String of length that", "length") {
                @Override
                protected Integer featureValueOf(String actual) {
                  return actual.length();
                }
        };
}



5. Exercise: Writing your custom Hamcrest matcher using TypeSafeMatcher



It is possible to write your custom Hamcrest matcher by extending TypeSafeMatcher. In contrast to BaseMatcher the TypeSafeMatcher class automatically checks for null values, checks the type and casts appropriately before delegating to matchesSafely(). It provides type safety by default. The following is an example for defining a matcher which allows testing if a String matches a regular expression.


TypeSafeMatcher를 extends하여 custom Hamcrest matcher를 작성할 수 있습니다. BaseMatcher와 달리 TypeSafeMatcher 클래스는 자동으로 null 값을 확인하고, types를 검사하고 matchesSafely ()에 위임하기 전에 적절하게 형 변환합니다. 기본적으로 type safety 을 제공합니다. 다음은 문자열이 정규 표현식 regular expression 과 일치하는지 테스트 할 수있는 matcher를 정의하는 예제입니다.


import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;

public class RegexMatcher extends TypeSafeMatcher<String> {

        private final String regex;

        public RegexMatcher(final String regex) {
                this.regex = regex;
        }

        @Override
        public void describeTo(final Description description) {
                description.appendText("matches regular expression=`" + regex + "`");
        }

        @Override
        public boolean matchesSafely(final String string) {
                return string.matches(regex);
        }


         // matcher method you can call on this matcher class
    public static RegexMatcher matchesRegex(final String regex) {
        return new RegexMatcher(regex);
    }
}


The following snippet gives an example how to use it.


다음 snippet에는 이를 사용하는 예가 나와 있습니다.


package com.vogella.android.testing.applicationtest;


import org.junit.Test;

import static org.hamcrest.MatcherAssert.assertThat;

public class TestCustomMatcher {

    @Test
    public void testRegularExpressionMatcher() throws Exception {
        String s ="aaabbbaaaa";
        assertThat(s, RegexMatcher.matchesRegex("a*b*a*"));
    }

}


6. Exercise: Combining matchers


Combining matchers is supported by Hamcrest out of the box but it has the limitation that the error is hard to read:


matchers를 결합하는 것은 Hamcrest에 오류가 읽기 어렵다는 제한이 있습니다.

@Test
public void () {
    List<Integer> list = new ArrayList<>();
    assertThat(list, both(hasSize(1)).and(contains(42)));
}
Expected: (a collection with size <1> and iterable containing [<42>])
     but: a collection with size <1> collection size was <0>.


This not very readable.


이렇게 가독성이 떨어집니다.



6.1. Target



We want to write our own MatcherCombiner that provides us with a readable error message, even when multiple matchers fail.


우리는 multiple matchers가 fail하더라도 가독성있는 에러 메시지를 제공하는 MatcherCombiner를 별도로 작성하려고합니다.



6.2. Create MatchCombiner



We do this by inheriting from BaseMatch and by providing a starting method that let’s us chain matchers together. The matchers get saved in a list that we iterate over during the matching phase.


우리는 BaseMatch로부터 상속하고 chain matcher를 함께 묶어주는 것을 시작하면서 이 작업을 수행합니다. matchers는 matching phase 동안에 반복되는 list 저장됩니다.


public class MatcherCombinator<T> extends BaseMatcher<T> {
    private final List<Matcher<? super T>> matchers = new ArrayList<>();
    private final List<Matcher<? super T>> failedMatchers = new ArrayList<>();

    private MatcherCombinator(final Matcher<? super T> matcher) {
        matchers.add(matcher);
    }

    public MatcherCombinator<T> and(final Matcher<? super T> matcher) {
        matchers.add(matcher);
        return this;
    }

    @Override
    public boolean matches(final Object item) {
        boolean matchesAllMatchers = true;
        for (final Matcher<? super T> matcher : matchers) {
            if (!matcher.matches(item)) {
                failedMatchers.add(matcher);
                matchesAllMatchers = false;
            }
        }
        return matchesAllMatchers;
    }

    @Override
    public void describeTo(final Description description) {
        description.appendValueList("\n", " " + "and" + "\n", "", matchers);
    }

    @Override
    public void describeMismatch(final Object item, final Description description) {
        description.appendText("\n");
        for (Iterator<Matcher<? super T>> iterator = failedMatchers.iterator(); iterator.hasNext();) {
            final Matcher<? super T> matcher = iterator.next();
            description.appendText("Expected: <");
            description.appendDescriptionOf(matcher).appendText(" but ");
            matcher.describeMismatch(item, description);
            if (iterator.hasNext()) {
                description.appendText(">\n");
            }
        }
    }

    public static <LHS> MatcherCombinator<LHS> matches(final Matcher<? super LHS> matcher) {
        return new MatcherCombinator<LHS>(matcher);
    }
}


To validate the implementation we write a new test.


implementation을 validate하기 위해 새로운 테스트를 작성합니다.


@Test
public void test() {
    List<Integer> list = new ArrayList<>();
    assertThat(list, matches(hasSize(1)).and(contains(42)));
}
java.lang.AssertionError:
Expected:
<a collection with size <1>> and
<iterable containing [<42>]>
     but:
Expected: <a collection with size <1> but collection size was <0>>
Expected: <iterable containing [<42>] but No item matched: <42>.


You can adjust this output in the describeMismatch method.


describeMismatch method 에서 이 output을 adjust 할 수 있습니다.



7. Grouping your matchers for import



If you define many custom matchers it might become tedious to import them one by one into your test files. By grouping them into a single class you can import them with one statement. You can also group them together with Hamcrest matchers.


많은 custom matchers를 정의하면 테스트 파일에 하나씩 import하는 것이 불편 할 수 있습니다. single class로 그룹화하여 하나의 statement로 가져올 수 있습니다. Hamcrest matchers와 함께 그룹화 할 수도 있습니다.



package com.vogella.hamcrest;
import com.vogella.hamcrest.matchers.RegexMatcher;
import org.hamcrest.Matcher;
import org.hamcrest.Matchers;

public class MyMatchers
{
    public static <T> Matcher<T> instanceOf(Class<T> target) {
        return Matchers.instanceOf(target);
    }

   public static Matcher<String> matchesRegex(String target) {
          return RegexMatcher.matchesRegex(target);
   }
}


In your test file:

import static com.vogella.hamcrest.MyMatchers.*;


















저작자 표시 비영리 동일 조건 변경 허락
신고


Cucumber Introduction:


Cucumber is a tool based on Behavior Driven Development (BDD) framework which is used to write acceptance tests for web application. It allows automation of functional validation in easily readable and understandable format (like plain English) to Business Analysts, Developers, Testers, etc.


Cucumber는 BDD (Behavior Driven Development) 프레임 워크를 기반으로 웹 응용 프로그램에 대한 acceptance 테스트를 작성하는 데 사용되는 도구입니다. 비즈니스 분석가, 개발자, 테스터 등이 쉽게 읽을 수 있고 이해할 수있는 형식 (일반 영어와 같은)으로 기능 검증을 자동화 할 수 있습니다.


Cucumber feature files can serve as a good document for all. There are many other tools like JBehave which also support BDD framework. Initially Cucumber was implemented in Ruby and then extended to Java framework. Both the tools support native JUnit.


Cucumber feature 파일은 훌륭한 문서 역할을 할 수 있습니다. BDD 프레임 워크를 지원하는 툴 들 로는 JBehave 등과 같은 다른 많은 도구들도 있습니다. 처음에 Cucumber는 Ruby에서 구현되었고 Java 프레임 워크로 확장되었습니다. 두 도구 모두 native JUnit을 지원합니다.


Behavior Driven Development is extension of Test Driven Development and it is used to test the system rather than testing the particular piece of code. We will discuss more about the BDD and style of writing BDD tests.


Behavior Driven Development는 Test Driven Development의 확장이며 특정 코드를 테스트하는 대신 시스템을 테스트하는 데 사용됩니다. 아래에 BDD 및 BDD 테스트 작성 스타일에 대해 자세히 설명합니다.


Cucumber can be used along with Selenium, Watir, and Capybara etc. Cucumber supports many other languages like Perl, PHP, Python, .Net etc. In this tutorial we will concentrate on Cucumber with Java as a language.


Cucumber는 Selenium, Watir, Capybara 등과 함께 사용할 수 있습니다. Cucumber는 Perl, PHP, Python, .NET 등의 많은 다른 언어를 지원합니다.이 튜토리얼에서는 Java와 함께 Cucumber를 언어로 사용합니다.




Cucumber Basics:


In order to understand cucumber we need to know all the features of cucumber and its usage.


Cucumber를 이해하기 위해서는 Cucumber의 모든 특징과 사용법을 알아야합니다.


#1) Feature Files:


Feature files are essential part of cucumber which is used to write test automation steps or acceptance tests. This can be used as live document. The steps are the application specification. All the feature files ends with .feature extension.


Feature file은 테스트 자동화 단계 또는 acceptance 테스트를 작성하는 데 사용되는 Cucumber의 핵심 부분입니다. 이것은 live document로 사용할 수 있습니다. steps는 application specification입니다. 모든 Feature file은 .feature 확장자로 끝납니다.



Sample feature file:

Feature: Login Functionality Feature

In order to ensure Login Functionality works,
I want to run the cucumber test to verify it is working

Scenario: Login Functionality

Given user navigates to SOFTWARETETINGHELP.COM
When user logs in using Username as “USER” and Password “PASSWORD”
Then login should be successful

Scenario: Login Functionality

Given user navigates to SOFTWARETETINGHELP.COM
When user logs in using Username as “USER1” and Password “PASSWORD1”
Then error message should be thrown


#2) Feature:


This gives information about the high level business functionality (Refer to previous example) and the purpose of Application under test. Everybody should be able to understand the intent of feature file by reading the first Feature step. This part is basically kept brief.


여기에는 대략적인 개념의 business functionality (이전 예 참조) 및 테스트중 인 응용 프로그램의 목적에 대한 정보가 있습니다. 첫 번째 Feature step을 읽으면 누구나 이 Feature file의 의도를 이해할 수 있어야 합니다. 이 부분은 기본적으로 간략하게 작성합니다.


#3) Scenario:

Basically a scenario represents a particular functionality which is under test. By seeing the scenario user should be able to understand the intent behind the scenario and what the test is all about. Each scenario should follow given, when and then format. This language is called as “gherkin”.


기본적으로 시나리오는 테스트중인 특정 기능을 나타냅니다. 시나리오 사용자는 시나리오의 의도와 그 테스트가 무엇인지 이해할 수 있어야합니다. 각 시나리오는 주어진 시간과 형식을 따라야합니다. 이 언어는 "작은 Cucumber (gherkin)"라고 불립니다.


  1. Given: As mentioned above, given specifies the pre-conditions. It is basically a known state.
  2. When: This is used when some action is to be performed. As in above example we have seen when the user tries to log in using username and password, it becomes an action.
  3. Then: The expected outcome or result should be placed here. For Instance: verify the login is successful, successful page navigation.
  4. Background: Whenever any step is required to perform in each scenario then those steps needs to be placed in Background. For Instance: If user needs to clear database before each scenario then those steps can be put in background.
  5. And: And is used to combine two or more same type of action.

Example:

Feature: Login Functionality Feature

Scenario: Login Functionality
Given user navigates to SOFTWARETETINGHELP.COM
When user logs in using Username as “USER”
And password as “password”
Then login should be successful
And Home page should be displayed

Example of Background:

Background:

Given user logged in as databases administrator
And all the junk values are cleared


#4) Scenario Outline:

Scenario outlines are used when same test has to be performed with different data set. Let’s take the same example. We have to test login functionality with multiple different set of username and password.

시나리오 개요는 동일한 테스트가 여러 다른 data set로 수행되어야 할 때 사용됩니다. 같은 예를 들어 봅시다. 여러 다른 사용자 이름 및 비밀번호 세트로 로그인 기능을 테스트해야합니다.


Feature: Login Functionality Feature

In order to ensure Login Functionality works,
I want to run the cucumber test to verify it is working

Scenario Outline: Login Functionality

Given user navigates to SOFTWARETESTINGHELP.COM
When user logs in using Username as <username> and Password <password>
Then login should be successful

Examples:
|username         |password          |
|Tom                     |password1        |
|Harry                   |password2        |
|Jerry                    |password3        |

Note:

  1. As shown in above example column names are passed as parameter to When statement.
  2. In place of Scenario, you have to use Scenario Outline.
  3. Examples are used to pass different arguments in tabular format. Vertical pipes are used to separate two different columns. Example can contain many different columns.

     
    위의 예에서와 같이 열 이름은 매개 변수로 When 문에 전달됩니다.
    Scenario 대신 Scenario Outline을 사용해야합니다.
    이 예제는 다른 인수를 표 형식으로 전달하는 데 사용됩니다. Vertical pipes는 두 개의 서로 다른 columns을 분리하는 데 사용됩니다. 이 예제에 많은 다른 열을 포함 할  수 있습니다.




#5) Tags:

Cucumber by default runs all scenarios in all the feature files. In real time projects there could be hundreds of feature file which are not required to run at all times.


기본적으로 Cucumber는 모든 Feature file에서 모든 시나리오를 실행합니다. 실시간 프로젝트에는 항상 실행될 필요가 없는 수백 개의 Feature file이있을 수 있습니다.


For instance: Feature files related to smoke test need not run all the time. So if you mention a tag as smokeTest in each feature file which is related to smoke test and run cucumber test with @SmokeTest tag . Cucumber will run only those feature files specific to given tags. Please follow the below example. You can specify multiple tags in one feature file.


예 : smoke test와 관련된 Feature file은 항상 실행될 필요는 없습니다. 따라서 smoke test와 관련된 각 Feature file에서 smokeTest로 태그를 언급하고 @SmokeTest 태그로 Cucumber 테스트를 실행하면됩니다. Cucumber는 특정 태그에 해당하는 Feature file 만 실행합니다. 아래의 예를 따르십시오. 하나의 Feature file에 여러 개의 태그를 지정할 수 있습니다.


Example of use of single tags:


@SmokeTest

Feature: Login Functionality Feature

In order to ensure Login Functionality works,
I want to run the cucumber test to verify it is working

Scenario Outline: Login Functionality

Given user navigates to SOFTWARETESTINGHELP.COM
When user logs in using Username as <username> and Password <password>
Then login should be successful

Examples:
|username         |password          |
|Tom     |password1        |
|Harry   |password2        |
|Jerry    |password3        |

Example of use of multiple tags:


As shown in below example same feature file can be used for smoke test scenarios as well as for login test scenario. When you intend to run your script for smoke test then use @SmokeTest. Similarly when you want your script to run for Login test use @LoginTest tag.

아래 예제에서와 같이 로그인 테스트 시나리오는 물론 Smoke Test 시나리오에도 동일한 Feature file을 사용할 수 있습니다. Smoke Test를 위해 스크립트를 실행하려면 @SmokeTest를 사용하십시오. 마찬가지로 로그인 테스트를 위해 스크립트를 실행하려면 @LoginTest 태그를 사용하십시오.


Any number of tags can be mentioned for a feature file as well as for scenario.


Feature file뿐만 아니라 시나리오에 대해서도 임의의 수의 태그를 사용 할 수 있습니다.


@SmokeTest @LoginTest


Feature: Login Functionality Feature

In order to ensure Login Functionality works,
I want to run the cucumber test to verify it is working

Scenario Outline: Login Functionality

Given user navigates to SOFTWARETETINGHELP.COM
When user logs in using Username as <username> and Password <password>
Then login should be successful

Examples:
|username         |password          |
|Tom     |password1        |
|Harry   |password2        |
|Jerry    |password3        |


Similarly you can specify tags to run specific scenario in a feature file. Please check below example to run specific scenario.


마찬가지로 태그를 지정하여 Feature file에서 특정 시나리오를 실행할 수 있습니다. 특정 시나리오를 실행하려면 아래 예제를 확인하십시오.


Feature: Login Functionality Feature

In order to ensure Login Functionality works,
I want to run the cucumber test to verify it is working

@positiveScenario
Scenario: Login Functionality

Given user navigates to SOFTWARETETINGHELP.COM
When user logs in using Username as “USER” and Password “PASSWORD”
Then login should be successful

@negaviveScenario
Scenario: Login Functionality

Given user navigates to SOFTWARETETINGHELP.COM
When user logs in using Username as “USER1” and Password “PASSWORD1”
Then error message should throw



#6) Junit Runner:


To run the specific feature file cucumber uses standard Junit Runner and specify tags in @Cucumber. Options. Multiple tags can be given by using comma separate. Here you can specify the path of the report and type of report you want to generate.


특정 Feature file을 실행하려면 cucumber가 표준 Junit Runner를 사용하고 @Cucumber에 태그를 지정하십시오. 옵션. 쉼표로 구분하여 여러 태그를 지정할 수 있습니다. 여기에서 생성하려는 보고서의 경로와 유형을 지정할 수 있습니다.


Example of Junit Runner:

1import cucumber.api.junit.Cucumber;</pre>
2import org.junit.runner.RunWith;
3@RunWith(Cucumber.class)
4@Cucumber.Options(format={"SimpleHtmlReport:report/smokeTest.html"},tags={"@smokeTest"})
5Public class JUnitRunner {
6}


Similarly you can give instruction to cucumber to run multiple tags. Below example illustrates how to use multiple tags in cucumber to run different scenarios.


마찬가지로 여러 개의 태그를 실행하기 위해 Cucumber에게 지시를 내릴 수 있습니다. 아래 예제는 Cucumber에서 여러 개의 태그를 사용하여 다른 시나리오를 실행하는 방법을 보여줍니다.


1import cucumber.api.junit.Cucumber;
2 import org.junit.runner.RunWith;
3 @RunWith(Cucumber.class)
4 @Cucumber.Options(format={"SimpleHtmlReport:report/smokeTest.html"},tags={"@smokeTest",”@LoginTest”})
5 Public class JUnitRunner {
6}



#7) Cucumber Report:


Cucumber generates its own html format. However better reporting can be done using Jenkins or bamboo tool. Details of reporting are covered in next topic of cucumber.


Cucumber는 자체적으로 HTML 형식을 생성합니다. Jenkins 또는 bamboo 도구를 사용하여 더 나은 보고를 수행 할 수 있습니다. 보고의 세부 사항은 Cucumber의 다음 주제에서 다룹니다.


Cucumber Project Setup:


Detail explanation of cucumber project set up is available separately in next tutorial. Please refer to Cucumber Tutorial Part2 from more information about project setup. Remember there is no extra software installations required for cucumber.


Cucumber 프로젝트 설정에 대한 자세한 설명은 다음 자습서에서 별도로 설명됩니다. 프로젝트 설정에 대한 자세한 내용은 Cucumber Tutorial Part2를 참조하십시오. Cucumber에 필요한 추가 소프트웨어 설치가 없음을 기억하십시오.


Implementation of Feature file:

We have to implement these steps in Java in order to test the feature files. Need to create a class which contains those given, when and then statements. Cucumber uses its annotations and all the steps are embedded in those annotations (given, when, then).Each phrase starts with “^” so that cucumber understands the start of the step. Similarly each step ends with “$”. User can use regular expressions to pass different test data. Regular expressions take data from feature steps and passes to step definitions. The order of parameters depends how they are passed from feature file. Please refer next tutorial for project setup and mapping between feature files and java classes.


Feature file을 테스트하려면 Java에서 이러한 steps를 구현해야합니다. 주어진, when 및 then 문을 포함하는 클래스를 작성해야합니다. Cucumber는 annotations을 사용하고 모든 step들은 annotations에 포함되어 있습니다 (given, when, then). 각 phrase는 "^"로 시작하여 Cucumber가 단계의 시작을 이해할 수 있도록합니다. 마찬가지로 각 단계는 "$"로 끝납니다. 사용자는 regular expressions을 사용하여 다른 테스트 데이터를 전달할 수 있습니다. 정규식 regular expressions은 feature steps에서 데이터를 가져 와서 step definitions로 전달합니다. 매개 변수 parameters 순서는 feature file에서 전달되는 방법에 따라 다릅니다. 피쳐 파일과 자바 클래스 간의 프로젝트 설정과 매핑에 대해서는 다음 튜토리얼을 참조하십시오.


Example:


Below example is to illustrate how feature files can be implemented.


아래 예제는 Feature file을 구현하는 방법을 보여줍니다.


In this example we have not used any selenium API. This is to just show how cucumber works as standalone framework. Please follow next tutorial for selenium integration with cucumber.


이 예제에서는 selenium API를 사용하지 않았습니다. Cucumber가 독립 프레임 워크로 어떻게 작동하는지 보여주기위한 것입니다. selenium과 Cucumber의 통합에 대한 내용은 next tutorial을 참조하세요.


1public class LoginTest {
2@Given("^user navigates to SOFTWARETETINGHELP.COM$")
3public void navigatePage() {
4system.out.println(“Cucumber executed Given statement”);
5}
6@When("^user logs in using Username as \"(.*)\" and Password \"(.*)\"$")
7public void login(String usename,String password) {
8system.out.println(“Username is:”+ usename);
9system.out.println(“Password is:”+ password);
10}
11@When("^click the Submit button$")
12public void clickTheSubmitButton() {
13system.out.println(“Executing When statement”)
14}
15@Then("^Home page should be displayed$")
16public void validatePage() {
17system.out.println(“Executing Then statement”)
18}
19@Then("^login should be successful$")
20public void validateLoginSuccess() {
21system.out.println(“Executing 2<sup>nd</sup> Then statement”)
22}
23}


When you execute cucumber runner class, cucumber will start reading feature file steps. For example, when you execute @smokeTest, cucumber will read Feature step and Given statement of scenario. As soon as cucumber finds Given statement, same Given statement will be searched in your java files. If same step is found in java file then cucumber executes the function specified for the same step otherwise cucumber will skip the step.


Cucumber runner class를 실행하면 Cucumber가 feature file steps를 읽습니다. 예를 들어 @smokeTest를 실행하면 cucumber는 Feature step과 Given of scenario 문을 읽습니다. Cucumber가 Given 문을 찾자마자 java 파일에서 동일한 Given 문이 검색됩니다. java 파일에서 동일한 단계가 발견되면 cucumber는 동일한 단계에 대해 지정된 함수를 실행하고 그렇지 않은 경우 그 step을 건너 뜁니다.


Conclusion:


In this tutorial, we have covered features of cucumber tool and its usage in real time scenario.
Cucumber is a most favorite tool for many projects as it is easy to understand, readable and contains business functionality.


이 튜토리얼에서는 Cucumber 도구의 기능과 그 사용법을 real time scenario 로 다루었습니다.


Cucumber는 이해하기 쉽고 읽기 쉽고 비즈니스 기능을 포함하고있어 많은 프로젝트에서 가장 많이 사용되는 도구입니다.


In the next chapter we will cover how to setup a cucumber – java project and how to integrate Selenium WebDriver with Cucumber.


다음 장에서는 Cucumber 자바 프로젝트를 설정하는 방법과 Selenium WebDriver를 Cucumber와 통합하는 방법에 대해 설명합니다.


저작자 표시 비영리 동일 조건 변경 허락
신고

티스토리 툴바