Mock synchronization with real implementations

The synchronization problem pops up whenever test strategies are discussed. Basically - due to the additional load that mokas create for developers and also the risks of mooks diverging from real dependencies.



So, in what way is it cheaper for us to ensure the synchronization of mokas with real implementations?



For synchronization, we can write a test that performs the same checks against mok and real implementation.



It looks something like this (I write without DI, but with DI it is simpler and more correct):



public abstract class AbstractValidOrderDaoTest(){ Dao dao; public abstract arrange(); @Test public void whenValidOrderInDb_thenReturnValidOrder(){ arrange(); Order order = dao.retrieve(); assertNotNull(order); assertNotNull(order.getCustomerName()); //    } } public class ValidOrderDaoTest extends AbstractOrderDaoTest(){ @Override public void arrange(){ dao = new FakeValidOrderDao(); } } public class OrderDaoTest extends AbstractOrderDaoTest(){ @Override public void arrange(){ dao = new RealOrderDao(new ValidOrderDataSource(url, user, pwd)); } }
      
      





OrderDaoTest works against a real object with underlying moq or real dependency, and ValidOrderDaoTest works against mok.



If ValidOrderDataSource is a real base, then OrderDaoTest will be in a separate package and run as part of integration tests, which may crash from time to time when updating the database, for example. This should not interfere with CI \ CD.



If ValidOrderDataSource is a mock database, then OrderDaoTest will run along with the rest of the unit tests.



Since Mock synchronization involves testing a real class, then for

the real class will have to dabble its underlying dependencies. Moreover, the underlying Mok-addiction should behave in accordance with the scenario of the overlying Mok. In our case, this

ValidOrderDataSource.



If you think about it, it makes sense - any statement about the behavior of higher classes implicitly implies some scenario in the underlying ones. If the controller returns something from the service, it would be nice if the base could provide it.



Conversely, higher classes often live with unrealistic ideas about lower classes, so it’s not bad to remove unnecessary scripts.



The recursion suggests that in order to make the top-level mock synchronized, you need to start synchronization of all underlying mocks up to external dependencies.



This makes the system specification even more transparent, since more general and abstract scenarios rely on more private ones.



Also note that there are mokas that do not need to be synchronized. Those. we do not have such a real implementation that would need to be cross-tested. This applies to major error scenarios. EmptyResultException_Datasource e.g. This greatly reduces the number of cross-tests needed.



Synchronization is certainly needed by real external dependencies, such as queues, external services, databases - especially with regard to the data that they take and return.



If the external service suddenly changes, which is often in the development stage, we have no way to check its behavior if we do not write a synchronization test.



In terms of labor intensity. In itself, we already have a real class test with some arbitrary mock dependencies. Compared to unsynchronized tests, we need to do a few things.






All Articles