jasmine

study, share · 2017-12-20

← 리스트로

Jasmine 학습

1. 기본 사용법 (Test Suite and Spec)
  • describe함수는 spec을 그룹화 합니다.
  • describe 함수는 suite의 제목과 구현하는 코드블록을 인자로 갖는다.
  • test spec은 it 함수로 정의한다.
describe("A suite", function() {
    it("contains spec with an expectation", function() {
      expect(true).toBe(true);
    });
});
2. 평가
  • expect는 평가의 대상이 되는 값이다.
  • toBe 는 Matcher로 예상값을 예측한다 (toBe 외에 많은 Matcher들이 있다)
  • toBe (정확이 같은 객체인지 평가)
it("and has a positive case", function() {
    expect(true).toBe(true);
});
  • toBe의 부정 평가
it("and can have a negative case", function() {
    expect(false).not.toBe(true);
});
  • toEqual (값의 동등성 평가)
it("works for simple literals and variables", function() {
    var a = 12;
    expect(a).toEqual(12);
});
  • toMatch (정규표현식을 이용해 평가)
it("The 'toMatch' matcher is for regular expressions", function() {
  var message = "foo bar baz";

  expect(message).toMatch(/bar/);
  expect(message).toMatch("bar");
  expect(message).not.toMatch(/quux/);
});
  • toBeDefined or toBeUndefined (값이 정의되어 있는지 평가)
it("The 'toBeDefined' matcher compares against `undefined`", function() {
  var a = {
    foo: "foo"
  };

  expect(a.foo).toBeDefined();
  expect(a.bar).not.toBeDefined();
});
it("The `toBeUndefined` matcher compares against `undefined`", function() {
  var a = {
    foo: "foo"
  };

  expect(a.foo).not.toBeUndefined();
  expect(a.bar).toBeUndefined();
});
  • toBeNull (변수가 null인지 평가)
it("The 'toBeNull' matcher compares against null", function() {
  var a = null;
  var foo = "foo";

  expect(null).toBeNull();
  expect(a).toBeNull();
  expect(foo).not.toBeNull();
});
  • toBeTruthy, toBeFalsy (값이 true인지, flase 인지 평가)
it("The 'toBeTruthy' matcher is for boolean casting testing", function() {
  var a, foo = "foo";

  expect(foo).toBeTruthy();
  expect(a).not.toBeTruthy();
});
  • toContain (배열 또는 스트링의 포함여부 평가)
it("works for finding an item in an Array", function() {
  var a = ["foo", "bar", "baz"];

  expect(a).toContain("bar");
  expect(a).not.toContain("quux");
});
it("also works for finding a substring", function() {
  var a = "foo bar baz";

  expect(a).toContain("bar");
  expect(a).not.toContain("quux");
});
  • toBeLessThan, toBeGreaterThan(값이 작은지 큰지 평가)
it("The 'toBeLessThan' matcher is for mathematical comparisons", function() {
  var pi = 3.1415926,    e = 2.78;
  expect(e).toBeLessThan(pi);
  expect(pi).not.toBeLessThan(e);
});
it("The 'toBeGreaterThan' matcher is for mathematical comparisons", function() {
  var pi = 3.1415926,
    e = 2.78;

  expect(pi).toBeGreaterThan(e);
  expect(e).not.toBeGreaterThan(pi);
});
  • toBeCloseTo(소수점아래 몇자리까지 같은지 평가)
it("The 'toBeCloseTo' matcher is for precision math comparison", function() {
  var pi = 3.1415926,
    e = 2.78;

  expect(pi).not.toBeCloseTo(e, 2);
  expect(pi).toBeCloseTo(e, 0);
});
  • toThrow(예외가 제대로 던져 지는지 평가)
it("The 'toThrow' matcher is for testing if a function throws an exception", function() {
  var foo = function() {
    return 1 + 2;
  };
  var bar = function() {
    return a + 1;
  };
  var baz = function() {
    throw 'what';
  };

  expect(foo).not.toThrow();
  expect(bar).toThrow();
  expect(baz).toThrow('what');
});
2. spec을 강제로 실패시킴
  • fail function을 사용
describe("A spec using the fail function", function() {
  it("should not call the callBack", function() {
      fail("Callback has been called");
  });
});
2. Setup and Teardown
  • beforeEach, afterEach (각 스팩을 실행할때마다, 각 스팩을 실행한 후에)
describe("A spec using beforeEach and afterEach", function() {
  var foo = 0;

  beforeEach(function() {
    foo += 1;
  });

   afterEach(function() {
    foo = 0;
  });

  it("is just a function, so it can contain any code", function() {
    expect(foo).toEqual(1);
  });

  it("can have more than one expectation", function() {
    expect(foo).toEqual(1);
    expect(true).toEqual(true);
  });
});
  • beforeAll, afterAll (모든 스팩을 실행하기 전에, 모든 스팩을 실행한 후에ss)
  • 동일한 수트안의 함수는 동일은 오브젝트 this를 갖는다
describe("A spec using beforeAll and afterAll", function() {
  var foo;

  beforeAll(function() {
    foo = 1;
  });

  afterAll(function() {
    foo = 0;
  });

  it("sets the initial value of foo before specs run", function() {
    expect(foo).toEqual(1);
    foo += 1;
  });

  it("does not reset foo between specs", function() {
    expect(foo).toEqual(2);
  });
});
3. 비활성화와 팬딩
  • Suite 비활성화
    • xdescribe를 사용
xdescribe("A spec", function() {

      var foo;

      beforeEach(function() {
          foo = 0;
          foo += 1;
      });

      it("is just a function, so it can contain any code",  function() {
          expect(foo).toEqual(1);
      });
});
  • Spec 비활성화
    • xit을 사용
    • function 인자를 넘기지 않음
    • pending 함수 사용
describe("Pending specs", function() {
      xit("can be declared 'xit'", function() {
          expect(true).toBe(false);
      });
      it("can be declared with 'it' but without a function");

      it("can be declared by calling 'pending' in the spec body", function() {
          expect(true).toBe(false);
          pending('this is why it is pending');
      });
});
4. 스파이 (이중테스트)
  • toHaveBeenCalled (메서드 호출되었는지 평가)
  • toHaveBeenCalledTimes (메서드 호출횟수 평가)
  • toHaveBeenCalledWith (메서드 호출중했던 인자중 같은 동일한 호출이 있었는지 평가)
  • and.callThrough (스파이로 연결된 메서드는 실제로 호출되지 않음으로 실제 실행시켜준다)
  • and.returnValue (스파이로 연결된 메서드가 실행될때마다 특정값을 리턴)
  • and.callFake (다른 함수로 바꿔치기)
  • and.throw (스파이로 연결된 메서드 호출시 오류를 던짐)
  • calls.any (적어도 한번 호출되었는지 평가)
  • calls.count (호출된 횟수를 반환)
  • calls.argsFor (호출 인덱스에 인자를 반환)
  • calls.allArgs (모든 호출에 대한 인수를 반환)
  • calls.all (호출의 모든 arguments 와컨텍스트를 반환)
  • calls.mostRecent (가장 최근호출의 모든 arguments 와컨텍스트를 반환)
  • calls.first (가장 첫번째 호출의 모든 arguments 와컨텍스트를 반환)
  • calls.reset (모든 스파이의 기록을 전부 지움)
  • jasmine.createSpy (빈껍데기 스파이 함수롤 만든다)
  • jasmine.createSpyObj (빈껍데기 스파이 객체를 만든다)
beforeEach(function() {
  foo = {
    setBar: function(value) {
      bar = value;
    }
  };

  spyOn(foo, 'setBar');

  foo.setBar(123);
  foo.setBar(456, 'another param');
});

it("tracks that the spy was called", function() {
  expect(foo.setBar).toHaveBeenCalled();
});

it("tracks that the spy was called x times", function() {
  expect(foo.setBar).toHaveBeenCalledTimes(2);
});

it("tracks all the arguments of its calls", function() {
  expect(foo.setBar).toHaveBeenCalledWith(123);
  expect(foo.setBar).toHaveBeenCalledWith(456, 'another param');
});

it("stops all execution on a function", function() {
  expect(bar).toBeNull();
});
5. jasmine.any or jasmine.anything
  • jsmine.any (생성자 이름을 비교하여 평가)
describe("jasmine.any", function() {
  it("matches any value", function() {
    expect({}).toEqual(jasmine.any(Object));
    expect(12).toEqual(jasmine.any(Number));
  });
});
  • jasmine.anything (실제값을 정확히 몰를경우 사용하면 true를 반환)
describe("jasmine.anything", function() {
  it("matches anything", function() {
    expect(1).toEqual(jasmine.anything());
  });

  describe("when used with a spy", function() {
    it("is useful when the argument can be ignored", function() {
      var foo = jasmine.createSpy('foo');
      foo(12, function() {
        return false;
      });

      expect(foo).toHaveBeenCalledWith(12, jasmine.anything());
    });
  });
});
6. 특정 부분의 매칭
  • jasmine.objectContaining (특정 키 / 값 에만 관심을 갖는 경우의 평가)
describe("jasmine.objectContaining", function() {
  var foo;

  beforeEach(function() {
    foo = {
      a: 1,
      b: 2,
      bar: "baz"
    };
  });

  it("matches objects with the expect key/value pairs", function() {
    expect(foo).toEqual(jasmine.objectContaining({
      bar: "baz"
    }));
    expect(foo).not.toEqual(jasmine.objectContaining({
      c: 37
    }));
  });
});
  • jasmine.arrayContaining (배열에 포함되어 있는지 매칭)
describe("jasmine.arrayContaining", function() {
  var foo;

  beforeEach(function() {
    foo = [1, 2, 3, 4];
  });

  it("matches arrays with some of the values", function() {
    expect(foo).toEqual(jasmine.arrayContaining([3, 1]));
    expect(foo).not.toEqual(jasmine.arrayContaining([6]));
  });
});
  • jasmine.stringMatching (문자열의 특정부분과 매칭을 평가)
describe('jasmine.stringMatching', function() {
  it("matches as a regexp", function() {
    expect({foo: 'bar'}).toEqual({foo: jasmine.stringMatching(/^bar$/)});
    expect({foo: 'foobarbaz'}).toEqual({foo: jasmine.stringMatching('bar')});
  });
});
7. Custom Matcher
  • 규칙이 애매한 경우 커스텀 매쳐 사용
describe("custom asymmetry", function() {
  var tester = {
    asymmetricMatch: function(actual) {
      var secondValue = actual.split(',')[1];
      return secondValue === 'bar';
    }
  };

  it("dives in deep", function() {
    expect("foo,bar,baz,quux").toEqual(tester);
  });

  describe("when used with a spy", function() {
    it("is useful for comparing arguments", function() {
      var callback = jasmine.createSpy('callback');

      callback('foo,bar,baz');

      expect(callback).toHaveBeenCalledWith(tester);
    });
  });
});
8. 시간에 종속적인 테스트
  • jasmine.clock().install (시간을 조작해야 하는 스팩에 사용)
  • jasmine.clock().uninstall (시간을 조작하는 테스트가 끝난 후 초기화)
  • jasmine.clock().tick (밀리세컨드 단위로 시간을 조작)
  • jasmine.clock().mockDate (현재 시간을 변경한 목 데이터 사용)
describe("Manually ticking the Jasmine Clock", function() {
  var timerCallback;

  beforeEach(function() {
    timerCallback = jasmine.createSpy("timerCallback");
    jasmine.clock().install();
  });
  afterEach(function() {
    jasmine.clock().uninstall();
  });

  it("causes a timeout to be called synchronously", function() {
    setTimeout(function() {
      timerCallback();
    }, 100);

    expect(timerCallback).not.toHaveBeenCalled();

    jasmine.clock().tick(101);

    expect(timerCallback).toHaveBeenCalled();
  });
});
9. 비동기 테스팅
  • done() (beforEach, it, afterEach는 비동기 수행이 완료되었을때 호출되는 아규먼트를 가지고 있다)
describe("Using callbacks", function() {

  beforeEach(function(done) {
    setTimeout(function() {
      value = 0;
      done();
    }, 1);
  });

  it("should support async execution of test preparation and expectations", function(done) {
    value++;
    expect(value).toBeGreaterThan(0);
    done();
  });
});
  • soon().then (promise 를 사용하여 비동기 처리를 할수있다.)
describe("Using promises", function() {
  if (!browserHasPromises()) {
    return;
  }

  beforeEach(function() {
    return soon().then(function() {
      value = 0;
    });
  });

  it("should support async execution of test preparation and expectations", function() {
    return soon().then(function() {
      value++;
      expect(value).toBeGreaterThan(0);
    });
  });
});
  • await soon() (async await을 사용하여 비동기 처리를 할 수 있다.)
  describe("Using async/await", function() {
    if (!browserHasAsyncAwaitSupport()) {
      return;
    }
    beforeEach(async function() {
      await soon();
      value = 0;
    });
    it("should support async execution of test preparation and expectations", async function() {
      await soon();
      value++;
      expect(value).toBeGreaterThan(0);
    });
  });
10. jasmin-ajax 플러그인
  • jasmine.Ajax.install() (사용할 ajax test의 spec의 시작전에 호출)
  • jasmine.Ajax.uninstall() (사용할 ajax test의 spec의 종류 후에 호출)
  • jasmine.Ajax.stubRequest() (호출 즉시 반환해야할때)
  • jasmine.Ajax.requests.mostRecent().respondWith (success호출을 기다려야할때)
describe("suite wide usage", function() {

  beforeEach(function() {
    jasmine.Ajax.install();
  });

  afterEach(function() {
    jasmine.Ajax.uninstall();
  });

  it("specifying response when you need it", function() {
    var doneFn = jasmine.createSpy("success");
    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function(args) {
      if (this.readyState == this.DONE) {
        doneFn(this.responseText);
      }
    };

    xhr.open("GET", "/some/cool/url");
    xhr.send();

    expect(jasmine.Ajax.requests.mostRecent().url).toBe('/some/cool/url');
    expect(doneFn).not.toHaveBeenCalled();

    jasmine.Ajax.requests.mostRecent().respondWith({
      "status": 200,
      "contentType": 'text/plain',
      "responseText": 'awesome response'
    });

    expect(doneFn).toHaveBeenCalledWith('awesome response');
  });

  it("allows responses to be setup ahead of time", function () {
    var doneFn = jasmine.createSpy("success");

    jasmine.Ajax.stubRequest('/another/url').andReturn({
      "responseText": 'immediate response'
    });

    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function(args) {
      if (this.readyState == this.DONE) {
        doneFn(this.responseText);
      }
    };

    xhr.open("GET", "/another/url");
    xhr.send();

    expect(doneFn).toHaveBeenCalledWith('immediate response');
  });
});