मैंने django rest auth से उपयोगकर्ता जानकारी प्राप्त करने के लिए एक सेवा बनाई है। तो मुझे 2 अलग-अलग अनुरोध चाहिए। एक प्रमाणीकरण टोकन प्राप्त करने के लिए और एक उपयोगकर्ता जानकारी प्राप्त करने के लिए।

userService सेवा में, मेरे पास login नामक एक विधि है जो 2 अन्य विधियों को कॉल करती है। उनमें से प्रत्येक एक अलग यूआरएल के लिए एक http अनुरोध भेजता है। login के व्यवहार का परीक्षण करने के लिए, मुझे उन 2 विधियों के अनुरोधों का मजाक उड़ाने की आवश्यकता है। पहली विधि एक Promise लौटाती है जिसमें प्रमाणीकरण कुंजी शामिल होती है, और दूसरी विधि एक Promise लौटाती है जिसमें उपयोगकर्ता ऑब्जेक्ट शामिल होता है। सेवा वर्ग में मेरा कोड यहां दिया गया है:

public getAuthToken(identifier: string, password: string) {
  const requestBody = is_valid_email(identifier) ? {email: identifier, password: password} :
                                                 {username: identifier, password: password};
  let savedToken = getFromStorage('auth');
  if (savedToken) {
    try {
      savedToken = JSON.parse(savedToken);
    } catch (e) {
      savedToken = null;
    }
  }
  return new Promise((resolve, reject) => {
    if (savedToken) {
      resolve(savedToken);
    } else {
      this.http.post<string>(APIUrlSolver.login, requestBody).subscribe(data => {
        const dataObj = JSON.parse(data);
        UserService._auth_token = dataObj['key'];
        resolve(dataObj['key']);
      }, error1 => {
        // Rejection code. removed for better reading
      });
    }
  });
}

public getUserProfile(): Promise<UserModel> {
  return new Promise<UserModel>((resolve, reject) => {
    this.http.get(APIUrlSolver.user).subscribe((data: string) => {
      const jsonData = JSON.parse(data);
      const userObj = new UserModel(jsonData.username, jsonData.email, jsonData.first_name, jsonData.last_name, jsonData.phone,
        jsonData.birth_date);
      UserService._user = userObj;
      resolve(userObj);
    }, error1 => {
      // Rejection code. removed for better reading
    });
  });
}

public login(identifier: string, password: string) {
  return new Promise((resolve, reject) => {
    this.getAuthToken(identifier, password).then(key => {
      this.getUserProfile().then(user => {
        // Will resolve user object
      }).catch(error => {
        UserService._auth_token = undefined;
        reject(error);
      });
    }).catch(reason => {
      UserService._auth_token = undefined;
      reject(reason);
    });
  });
}

मैंने निम्नलिखित कोड के साथ इस विधि का परीक्षण करने का प्रयास किया है:

      describe('userService', () => {
  let userService: UserService;
  let httpClient: HttpTestingController;
  const mockedUser = new UserModel();
  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
      providers: [UserService]
    });
    userService = TestBed.get(UserService);
    httpClient = TestBed.get(HttpTestingController);
  });

  afterEach(() => {
    httpClient.verify();
  });

    it('#login', () => {
    const authResponse = {key: '74f0d5ffb992f5f49533d25c686f36414e64482c'};
    const response = {username: 'daaaaaaab', email: 'test@test.ir', first_name: 'test', last_name: 'test', phone: '09123657894',
      birth_date: '2018-07-31'};
    const expectedUser = new UserModel(response.username, response.email, response.first_name, response.last_name, response.phone,
      response.birth_date);

    userService.login('identifier', 'password').then(user => {
      expect(user).toEqual(expectedUser);
      expect(userService.user).toEqual(expectedUser);
      });

    const req = httpClient.expectOne(APIUrlSolver.login);   // This response works correct
    expect(req.request.method).toBe('POST');
    req.flush(JSON.stringify(authResponse));

    const userReq = httpClient.expectOne(APIUrlSolver.user);    // I get error here
    expect(req.request.method).toBe('GET');
    userReq.flush(JSON.stringify(response));
    });

     });

लेकिन यह कोड हमेशा userReq पर विफल रहेगा। क्योंकि expectOne उठाता है:

 Error: Expected one matching request for criteria "Match URL: /user/user/", found none.

असली सवाल यह है कि मैं http अनुरोधों के इस क्रम का परीक्षण कैसे कर सकता हूं क्योंकि HttpClientTestingModule ने काम नहीं किया

7
Mr Alihoseiny 7 सितंबर 2018, 12:04

1 उत्तर

सबसे बढ़िया उत्तर

आप अपने HTTP क्लाइंट का मज़ाक उड़ाने के लिए TypeMoq का उपयोग करके देख सकते हैं। निम्नलिखित कोड आपको सही दिशा में भेजना चाहिए। हालांकि इसका परीक्षण नहीं किया जाता है।

describe('user service', () => {

  const tokenData = { key: 'asdasd' };
  const userResponse = { name: 'user', /* ... and so on */ };

  let mockHttpClient: TypeMoq.IMock<HttpClient>;
  let mockUserService: TypeMoq.IMock<UserService>;

  beforeAll(async(() => {

    mockHttpClient = TypeMoq.Mock.ofType<HttpClient>();
    mockHttpClient.setup(x => 
      x.get(TypeMoq.It.isValue(APIUrlSolver.login)).returns(() => of(tokenData))
    );
    mockHttpClient.setup(x => 
      x.get(TypeMoq.It.isValue(APIUrlSolver.user)).returns(() => of(userResponse))
    );

    mockUserService = TypeMoq.Mock.ofType<UserService>();

    TestBed
      .configureTestingModule({
        declarations: [],
        providers: [
          { provide: HttpClient, useValue: mockHttpService.object},
          { provide: UserService, useValue: mockUserService.object},
        ]
      })
      .compileComponents();
  }));

  let userService: UserService;

  beforeEach(async(() => {
    userService = TestBed.get(UserService);
  });

  it('login flow', async () => {
     const user = await userService.login('identifier', 'password');
     mockUserService.verify(x => x.getToken, TypeMoq.Times.once());
     mockUserService.verify(x => x.getUserProfile, TypeMoq.Times.once());
     mockHttpService.verify(x => x.get, TypeMoq.Times.exactly(2));
     // ... any other assertions
  });
});

आशा है इससे थोडी मदद मिलेगी :-)


संपादित करें

चूंकि आप इन-बिल्ट सामान का उपयोग करना चाहते हैं, इसलिए मैं आपके तर्क को एक देखने योग्य प्रवाह में बदलने की सलाह दूंगा। आपकी समस्या का कारण हो सकता है कि आपने सभी कॉलों का वादा किया हो, अवलोकन योग्य एपीआई का उपयोग नहीं कर रहा हो।

इस तरह मैं इसे लिखूंगा - आप इसे आजमा सकते हैं और देख सकते हैं कि यह मदद करता है :-)

public getAuthToken(identifier: string, password: string): Observable<string> {

  let savedToken = getSavedToken();
  if(savedToken) return of(savedToken);

  return this.http.post<string>(APIUrlSolver.login, getRequestBody(identifier, password)).pipe(
    // Instead of this mapping you can use `this.http.post<YourDataStructure>`
    // and the JSON deserialization will be done for you
    map(data => JSON.parse(data)),
    map(data => UserService._auth_token = data['key']),
    // You can either handle the error here or let it fall through and handle it later
    catchError(err => /* error handling code */)
  );

public getUserProfile(): Observable<UserModel> {
  return this.http.get(APIUrlSolver.user).pipe(
    // Again, if your response JSON already looks like the `UserModel`,
    // you can simply write `this.http.get<UserModel>` ...
    map(data => {
      let d = JSON.parse(data);
      return UserService._user = new UserModel(d.username, d.email, d.first_name, d.last_name, d.phone, d.birth_date);
    }),
    catchError(err => /* as stated before... */)
  );

public login(identifier: string, password: string) {
  return this.getAuthToken(identifier, password).pipe(
    switchMap(key => this.getUserProfile()),
    catchError(err => /* Your login-wide error handler */)
  );

फिर अपने परीक्षण में, आप परिणाम के लिए केवल लॉगिन विधि और subscribe का उपयोग करते हैं (then का उपयोग करने के बजाय - यह अब कोई वादा नहीं है)।

आपका अन्य परीक्षण सेटअप ठीक दिखता है - समस्या मेरी राय में वादों का उपयोग कर रही है।

5
Heehaaw 13 सितंबर 2018, 13:54