Any thoughts to support unit tests on private functions?

I lead a moderately large ReScript project (110k loc). As we have increased our team and more requirements are being developed, we have recently introduced testing.

But I face the problem of having to make some internal APIs public (expose them in .resi) to be able to unit-test some of the tricky implementation details. And LLMs, pick them up as actually public APIs and “reuse” them in unexpected places, creating unwanted coupling.

Ideally I would keep .resi files with only the public APIs. But then my tests need to always be done in terms of the observables of the API. This is not bad in itself, but some complex frameworks would benefit from smaller units of testing.

My proposal follows a similar “outlook” to the rust in-module tests with @test accompanied by a tool rescript test to collect and run them.

@test 
module InternalPrivateTest {
   @test
   let test_some_internal_property: unit => unit = () => {   
      throw(AssertionError("..."))
   } 
}

I understand there will be challenges of many kinds: async tests, how to interface the rescript test with other test runners (maybe not at all), etc.

In any case, I think this is conversation worth having.


Small rust example
#[cfg(test)]
mod tests {
    use super::*;
    use proptest::prelude::*;

    proptest! {
        #[test]
        fn convert_f32_to_totals(a: f32, b: f32) {
            let ta: Totalized<f32> = a.into();
            let tb: Totalized<f32> = b.into();
            assert_eq!(a.partial_cmp(&b).unwrap_or(Ordering::Equal), ta.cmp(&tb))
        }

        #[test]
        fn convert_f64_to_totals(a: f64, b: f64) {
            let ta: Totalized<f64> = a.into();
            let tb: Totalized<f64> = b.into();
            assert_eq!(a.partial_cmp(&b).unwrap_or(Ordering::Equal), ta.cmp(&tb))
        }

        #[test]
        fn convert_totals_back_to_f64(a: f64) {
            let ta: Totalized<f64> = a.into();
            let b: f64 = ta.into();
            assert!((a - b).abs() < 1e-10f64);
        }
    }
}
1 Like

there’s already a PPX for that I worked on quite some time ago but I have no idea if it still works today:

But yes it’s something we’ve discussed a few times in the core team, I think it’d be nice to have something with a simpler solution than a PPX.

1 Like