0

I think my problem is related to this issue: Tests pass when run individually but not when the whole test class run

My tests all pass individually but when i run the test class, two of them fail. Debugging shows that that assertEquals is expecting different states than given in the code, mainly the states from different tests. The solution should be using a @Before or @After and do a cleanup, but i am having troubles using that becouse the instance is Autowired from Spring.

Main question: Is my thinking right and how do i 'reset' the autowired instance?

@SpringBootTest
class StatementProcessorServiceTest {

    @Autowired
    StatementProcessorService statementProcessorService;

    private StatementProcessorInputModel setup(long id, boolean endbalanceCorrect) {
        StatementProcessorInputModel statementProcessorInputModel = new StatementProcessorInputModel();
        statementProcessorInputModel.startBalance = 1.00;
        statementProcessorInputModel.id= id;
        statementProcessorInputModel.startBalance = 1.00;
        statementProcessorInputModel.mutation = 1.00;
        statementProcessorInputModel.endBalance = endbalanceCorrect ? 2.00 : 1.00;
        return statementProcessorInputModel;
    }

    @Test
    void verify_with_all_good_settings()
    {
        StatementProcessorResponseModel sut;
        sut = statementProcessorService.validate(setup(1, true));
        Assert.assertEquals(sut.result, "SUCCESSFUL");
    }

    @Test
    void verify_with_good_settings_but_duplicated_reference()
    {
        StatementProcessorResponseModel sutFirst = statementProcessorService.validate(setup(2, true));
        Assert.assertEquals(sutFirst.result, "SUCCESSFUL");
        StatementProcessorResponseModel sutSecond;
        sutSecond = statementProcessorService.validate(setup(2, true));
        Assert.assertEquals(sutSecond.result, "DUPLICATE_REFERENCE");
    }

    @Test
    void verify_with_wrong_endBalance_and_good_reference()
    {
        StatementProcessorResponseModel sut = statementProcessorService.validate(setup(3, false));
        Assert.assertEquals(sut.result, "INCORRECT_END_BALANCE");
    }

    @Test
    void verify_with_all_wrong_settings()
    {
        StatementProcessorResponseModel sutFirst = statementProcessorService.validate(setup(4, true));
        Assert.assertEquals(sutFirst.result, "SUCCESSFUL");
        StatementProcessorResponseModel sutSecond = statementProcessorService.validate(setup(4, false));
        Assert.assertEquals(sutSecond.result, "DUPLICATE_REFERENCE_INCORRECT_END_BALANCE");
    }
}

Edit 1: Added Service code

@Component
public class StatementProcessorService {
    private StatementProcessorResponseModel responseModel = new StatementProcessorResponseModel();
    private static ArrayList<Long> usedReferences = new ArrayList<>();

    public StatementProcessorResponseModel validate(StatementProcessorInputModel inputModel){
        if(!validateUniqueReference(inputModel.transactionReference))
        {
            responseModel.errorRecords.add("account_number_of_ inCorrectEndBalance _record");
            responseModel.result = "DUPLICATE_REFERENCE";
        }

        if(!validateMutation(inputModel))
        {
            responseModel.errorRecords.add("account_number_of_ inCorrectEndBalance _record");
            if (!responseModel.result.isBlank()){
                responseModel.result = responseModel.result + "_INCORRECT_END_BALANCE";
            }
            else{
                responseModel.result = "INCORRECT_END_BALANCE";
            }
        }

        if (responseModel.result.isBlank()){
            responseModel.result = "SUCCESSFUL";
        }
        return responseModel;
    }
Michael
  • 83
  • 1
  • 9

2 Answers2

2

If you mark your test cases/classes which modify the database with @Transactional then the test runner will rollback the transaction after the test.

You can refer to the reference documentation regarding test transactions.

ptomli
  • 11,730
  • 4
  • 40
  • 68
  • For this project (It's a small hobby project) i do not use a database or JPA. – Michael May 05 '20 at 06:52
  • Presumably the StatementProcessorService is storing state _somewhere_. This state is what you're needing to reset. @Transactional would work if you're storing the state in a database, how you reset state for your scenario will depend on how you're storing it. – ptomli May 05 '20 at 06:53
  • I added my original Service code and you were right. After i moved the initiation of the ResponseModel to the method instead of the class, it resets every test and they pass. Thank you for your time and help! – Michael May 05 '20 at 07:04
  • Not sure I understand, but glad I could be of assistance :-) – ptomli May 05 '20 at 07:07
0

It seems you're not using a database to store state, so it's difficult to add a complete answer without knowing how you are storing this state. Regardless StatementProcessorService must be storing state somehow, so I'll try to illustrate how you can reset this state between tests, and perhaps you can adapt it to your situation.

Starting from a basic "it's stored in memory" example

class StatementProcessorService {
  // assuming you're storing state in memory for now
  // here we're just creating a shared map, which is where we presume you're putting data
  private Map<String, String> state = new HashMap<>();
}

The easiest way of doing this is to expose a method to reset the state from outside the StatementProcessorService.

class StatementProcessorService {
  // ...

  /** Reset state */
  @VisibleForTesting
  public void reset() { state.clear(); }
}

You could also use an injected state holder, which during tests can itself expose a reset method

class StateHolder {
  // accessor/mutator methods
}

class TestStateHolder extends StateHolder {
  // ...

  public void reset() { ... }
}

class StatementProcessorService {
  @Autowired
  private StateHolder state;
}

And finally, you could just mock the StateHolder with Mockito

@SpringBootTest
class StatementProcessorServiceTest {
  @MockBean StateHolder state;
}

As normal with Spring, there are a lot of ways of achieving your goal.

ptomli
  • 11,730
  • 4
  • 40
  • 68