Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Testing with Either #80

Closed
LittleFireflies opened this issue Jun 29, 2021 · 8 comments
Closed

Testing with Either #80

LittleFireflies opened this issue Jun 29, 2021 · 8 comments

Comments

@LittleFireflies
Copy link

LittleFireflies commented Jun 29, 2021

Hi, I'm currently working on a clean architecture project using Flutter.
I find dartz package is useful to bring either success or failure values.

But, i have issues when it comes to testing.

This is is my test case which won't passed:

test('should load list of cast from repository', () async {
    // arrange
    final tId = 1;
    final tCast = Cast(...);
    final tCastList = <Cast>[tCast];

    when(mockCreditsRepository.loadCastByMovie(tId))
        .thenAnswer((_) async => Right(<Cast>[tCast]));
    // act
    final result = await usecase.execute(tId);
    // assert
    expect(result, Right(<Cast>[tCast]));
});

Those test will return as follows:

Expected: Right<dynamic, List<Cast>>:<Right([Cast(1, department, name, originalName, 0.0, profilePath, character)])>
  Actual: Right<Failure, List<Cast>>:<Right([Cast(1, department, name, originalName, 0.0, profilePath, character)])>

But, somehow it passed when I put both value in the same variable.

final tCastList = <Cast>[tCast];

when(mockCreditsRepository.loadCastByMovie(tId))
        .thenAnswer((_) async => Right(tCastList));
    // act
    final result = await usecase.execute(tId);
    // assert
    expect(result, Right(tCastList));

I think it is because i create 2 difference instance for the test. Is there a way to evaluate only the value of either instead of comparing the instance?

@LittleFireflies
Copy link
Author

I use equatable package, so two objects being compared by the value it holds on, instead of the instance. This code below will return true:
expect(<Cast>[tCast], <Cast>[tCast]); // return true

@Babwenbiber
Copy link

I have the very same problem.
I wrote the simplest test you can have for that.
Furthermore, I am sure, that in Flutter 1 this would work.


import 'package:dartz/dartz.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
  String expectedLeft = "lefti";
  List<int> expectedRight = [1, 2, 3, 4, 5];

  group("test dartz", () {
    test("test left", () {
      final res = getExpected(true);
      expect(res, Left(expectedLeft));
    });

    test("test right", () {
      final res = getExpected(false);
      expect(res, Right(expectedRight));
    });
  });
}

Either<String, List<int>> getExpected(bool isLeft) {
  if (isLeft) {
    return Left("lefti");
  } else {
    return Right([1, 2, 3, 4, 5]);
  }
}


output:

package:test_api                                   expect
package:flutter_test/src/widget_tester.dart 440:3  expect
test/core/data/datasources/dartz_test.dart 16:7    main.<fn>.<fn>

Expected: Right<dynamic, List<int>>:<Right([1, 2, 3, 4, 5])>
  Actual: Right<String, List<int>>:<Right([1, 2, 3, 4, 5])>

@spebbe
Copy link
Owner

spebbe commented Jun 29, 2021

Hi @LittleFireflies and @Babwenbiber!

This looks like a duplicate of #39 and #45 . Basically, Dart List == doesn't check deep equality by default, but expect special treats "naked" Lists.

expect([1] == [1], true) fails for the same reason.

See the linked tickets for some alternative solutions!

@LittleFireflies
Copy link
Author

Ok, well noted @spebbe. Thanks for answering. So it's because of the naked list.

I'm curious, is it possible to add listEquals() as the default comparison for List by default? Because I used to have this problem too when I still use operator and hashcode to compare object manually.

@spebbe
Copy link
Owner

spebbe commented Jun 30, 2021

In the context of tests, it might be possible to write custom matchers that would check for deep list equality in more cases.

For general code, even if changing the semantics of List equality were possible, it would probably break a lot of existing libraries that depend on == being roughly the same as identical for Lists.

@LittleFireflies
Copy link
Author

Well then. I'll use result.getOrElse() as a workaround for now. Thanks for the answer. Considered it done and close it.

@spebbe
Copy link
Owner

spebbe commented Jun 30, 2021

Cool! @LittleFireflies, if you haven't already seen it, the | operator is a shortcut for getOrElse(), so depending on your situation you might be able to just do result|null in your expectations.

@SuperMuel
Copy link

I wrote a package to simplify testing with dartz. It currently works for Options and Eithers.

If your class overrides ==, you can use the isRightOf (or isLeftOf) that checks whether the Either instance is actually a Right (or Left) instance containing the object you want :

test('gets the root user', (){
    Either<ApiFailure, User> result = getRootUser();
    final expectedUser = User(username='root'); // User class overrides ==
    expect(result, isRightOf(expectedUser));
});

If your object does not overrides == :
This is typically the case for Lists. For instance, given two lists var object1 = ['foo']; and var object2 = ['foo'];
Checking for equality object1 == object2 returns False. However the matcher equals will compare the content of the two lists and the following test is valid :

test('Test list equality',(){
    final object1 = ['foo'];
    final object2 = ['foo'];
    expect(object1, equals(object2));
}); // test successful

For cases like this, and more generic ones, we have the matcher isRightThat (or isLeftThat) in dartz_test

test('Test list equality in either',(){
    final object1 = ['foo'];
    Either either = Right(object1);
    expect(either, isRightThat(equals(['foo'])));
}); // test successful

The package also includes matchers for the Option type.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants