0

I am wondering if my approach to the service I am building and testing is the right approach or not. I have always designed my classes to be as encapsulated as possible. So when it came to building my angular services, I built them the same way.

Below is a snippet of how my service looks:

private postUrl = 'https://localhost:44359/api/posts';
private currentGetPostsUrl = `${this.postUrl}?page=${this.pageNumber}&pageSize=${this.pageSize}`;

private filteredPostListSource = new Subject<IPostViewDto[]>();
filteredPostList$ = this.filteredPostListSource.asObservable();

// post list returned from the api
private originalPostList: IPostViewDto[];
// filtered list that is displayed to user
private filteredPostList: IPostViewDto[];

//get a list of posts that are paginated
getPosts(): Observable < IPostViewDto[] > {
  const urlToFetch = `${this.postUrl}?page=${this.pageNumber}&pageSize=${this.pageSize}`;

  // if the post list exists, return that post list
  if(this.originalPostList) {
  return of(this.originalPostList);
}

return this.http.get<IPostViewDto[]>(urlToFetch, { observe: 'response' })
  .pipe(
    map((response: HttpResponse<IPostViewDto[]>) => {
      const paginationHeader = JSON.parse(response.headers.get('X-Pagination'));
      this.totalCount = paginationHeader.totalCount;
      this.originalPostList = response.body;
      this.filteredPostList = [...this.originalPostList];
      return response.body;
    }),
    catchError(err => this.errorHandler(err))
  );
}

Per above, I don't allow components to directly access the private variables and instead have methods through which all interaction is done. The issue here is that unit testing is a bit of a mess. If I want to correctly test that my getPosts() method correctly returns the list of posts in my originalPostList if it exists, I'd have to run it once after creating a stub value for the http get to ensure the private field gets set, then run it again and compare my stub value equals the 2nd run of getPosts().

This seems like its not only a bad unit test, but maybe the service itself is not built correctly to be tested.

What would be the best way to restructure this to be easily testable? Do I just create getters/setters and test against those? Or is my approach I described above valid?


Do note that the reason why I designed it this way is because I didn't want child components / other components to accidentally update these properties without an explicit method call (so that I can write tests to ensure that is the case). Its not because a single component is the only one accessing this service.

0

2 Answers 2

0

You can create either getter method for accessing private variable or you can change it to public and add readonly to it. That way other components/tests can access it but cannot change it.

In my opinion you should not have to call methods twice to test them. Taken from your example I would probably create a function that accepts GET parameters. Once you have that you can test that you are hitting correct API endpoint and getting correct data object via HttpClientTestingModule.

Sign up to request clarification or add additional context in comments.

Comments

-1

I agree that you should not access the private variables in your tests. If you do, your test will be useless when you need to do some refactoring.

I don't see an issue with calling the method twice in your tests. I am assuming it will happen in actual code since you are implementing a caching mechanism. "The more your tests resemble the way your software is used, the more confidence they can give you."

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.