Write Unit Tests for a Given Python Class, Covering Normal and Edge Cases
Company: Elsevier
Role: Data Scientist
Category: Software Engineering Fundamentals
Difficulty: easy
Interview Round: Technical Screen
A data scientist interview includes a short coding and testing exercise: you are given the implementation of a small Python class and asked to write test cases for it, mainly normal cases and edge cases.
The report does not describe the class that was provided. This version supplies a small class of the same kind so the exercise can be practiced:
```python
from collections import deque
class MovingAverage:
"""Mean of the most recent `window` values passed to add()."""
def __init__(self, window: int):
if not isinstance(window, int) or window <= 0:
raise ValueError("window must be a positive integer")
self.window = window
self._values = deque()
self._total = 0.0
def add(self, value: float) -> float:
"""Record a value and return the mean of the most recent `window` values."""
self._values.append(value)
self._total += value
if len(self._values) > self.window:
self._total -= self._values.popleft()
return self._total / len(self._values)
def current(self) -> float | None:
"""Return the mean of the most recent `window` values, or None before the first add()."""
if not self._values:
return None
return self._total / len(self._values)
```
Write a set of tests for this class with `pytest` or `unittest`. For each test, say what behavior it checks and what result you expect. Where the docstrings leave the intended behavior open, state the expectation you are testing against and the question you would put to the class's author.
```hint Organize the cases
Group cases by what they exercise: the constructor, the period before the window fills, the steady state once old values start dropping out, and inputs that add() should not accept.
```
```hint Look at the running total
The class never recomputes the mean from the stored values. Ask which inputs or sequences could make the running total disagree with the values actually in the window.
```
### Clarifying Questions
- Should add() reject non-numeric values, NaN or infinity, or is the caller trusted to pass finite numbers?
- Are `True` or `2.0` acceptable window sizes?
- Must returned means be exact, or is a small floating-point tolerance acceptable?
- If add() raises, should the object be left exactly as it was before the call?
- Which test framework is available?
### What a Strong Answer Covers
- Normal behavior checked against hand-computed means: the warm-up before the window fills, the sliding window once it is full, a window of one, and current() agreeing with the last add()
- Constructor validation at the boundary and with wrong types
- Invalid inputs to add() and the object's state after a rejected value
- The numerical weak points of a running total: tolerance for float means, NaN and infinity, and values of very different magnitudes
- Small, independent, clearly named tests, parametrized where natural, with open questions for the author kept separate from the tests
### Follow-up Questions
- Which of your tests fail against this implementation, and how would you change the class so they pass?
- How would you check the class against a simple reference implementation on many random inputs?
- If add() sits on a hot path, how would you check that its cost does not grow with the window size without writing a flaky timing test?
Overview: A data science coding exercise that gives you a small Python moving-average class and asks you to write unit tests for it, covering normal cases and edge cases. It tests how you organize test cases, define expected behavior where the docstrings are silent, compare floating-point results, and check the object's state after invalid input.
Read the full Elsevier Data Scientist interview experience this question came from