Three test methods dominate PCBA manufacturing: in-circuit test (ICT), functional test (FCT), and flying probe. Each catches different defects at different costs. Most production lines use two or three in combination. This guide compares them so you can choose the right test strategy for your product.
Quick Comparison
| ICT | FCT | Flying Probe | |
|---|---|---|---|
| What it tests | Individual components | Board-level behavior | Individual components |
| Defects caught | Wrong value, missing, short, open | Power, comms, firmware, performance | Same as ICT |
| Test time | 5-30 seconds | 30 seconds - 5 minutes | 1-10 minutes |
| Fixture cost | $5,000-50,000 | $1,000-10,000 | None (fixtureless) |
| NRE time | 4-8 weeks | 1-2 weeks | Hours (program only) |
| Volume sweet spot | 10K+ units/year | Any volume | Prototypes, < 5K units/year |
| Automation | Fully automated | Fully automated | Fully automated |
| Board access | Bed-of-nails (needs test pads) | Connectors + probes | Probes (no fixture) |
| Programming | Vendor software | Python/LabVIEW/custom | Vendor software |
In-Circuit Test (ICT)
ICT presses a bed-of-nails fixture against the board and tests each component individually. It verifies that the right components are in the right places with the right values.
What ICT Catches
| Defect | Detection Method |
|---|---|
| Wrong resistor value | Resistance measurement |
| Missing component | Open circuit detection |
| Solder short | Short circuit detection |
| Wrong polarity (capacitor, diode) | Capacitance/diode test |
| IC pin opens | Boundary scan (JTAG) |
| BGA connection issues | Limited (only accessible pins) |
ICT Costs
| Item | Typical Cost |
|---|---|
| Fixture (bed-of-nails) | $5,000-50,000 depending on board complexity |
| Fixture lead time | 4-8 weeks |
| ICT machine | $50,000-500,000 (capital) |
| Test time per board | 5-30 seconds |
| Program development | $2,000-10,000 |
When to Use ICT
- High volume (10K+ boards/year). The fixture cost amortizes over volume.
- Complex boards with many passives. ICT excels at verifying resistor/capacitor values.
- SMT assembly with known defect rates. ICT catches assembly defects before FCT.
- When you need fast test time. 5-30 seconds vs. minutes for FCT.
When to Skip ICT
- Low volume (< 5K/year). Fixture cost doesn't justify the volume.
- Simple boards (< 50 components). FCT alone catches most defects.
- Fast design iteration. Fixture changes with every board revision.
- BGA-heavy designs. ICT can't access BGA pads without boundary scan.
Functional Test (FCT)
FCT tests the board as a working system. You power it up, run the firmware, and verify behavior. FCT catches defects that ICT misses: firmware bugs, timing issues, analog performance, and system-level interactions.
What FCT Catches
| Defect | Detection Method |
|---|---|
| Voltage regulator failure | Power rail measurement |
| Wrong firmware | Version query |
| Communication failure | UART/SPI/I2C response check |
| Excessive current draw (short) | Current measurement |
| Wrong crystal frequency | Frequency measurement |
| ADC/DAC calibration drift | Analog measurement |
| Failed self-test | Firmware self-test command |
FCT Costs
| Item | Typical Cost |
|---|---|
| Test fixture (pogo pins + connectors) | $1,000-10,000 |
| Fixture lead time | 1-2 weeks |
| Instruments (DMM, PSU, etc.) | $2,000-20,000 (one-time, reusable) |
| Test time per board | 30 seconds - 5 minutes |
| Script development | Python + OpenHTF (free tools) |
When to Use FCT
- Every production board should get FCT. It's the final check before shipping.
- Any volume. Low fixture cost makes it viable even for 100 units/year.
- After ICT. FCT verifies system behavior that ICT can't test.
- As the only test for simple boards. If the board has < 50 components, FCT alone may suffice.
FCT with Python and TofuPilot
import openhtf as htffrom openhtf.plugs import BasePlugfrom openhtf.util import unitsfrom tofupilot.openhtf import TofuPilotclass BoardPlug(BasePlug): """Board interface for FCT.""" def setUp(self): self._voltages = iter([3.31, 5.01, 1.81]) self._current = 0.12 def read_voltage(self) -> float: return next(self._voltages) def read_current(self) -> float: return self._current def query_firmware(self) -> str: return "2.1.0" def tearDown(self): pass@htf.measures( htf.Measurement("rail_3v3").in_range(3.2, 3.4).with_units(units.VOLT), htf.Measurement("rail_5v0").in_range(4.8, 5.2).with_units(units.VOLT), htf.Measurement("rail_1v8").in_range(1.7, 1.9).with_units(units.VOLT),)@htf.plug(board=BoardPlug)def test_power(test, board): test.measurements.rail_3v3 = board.read_voltage() test.measurements.rail_5v0 = board.read_voltage() test.measurements.rail_1v8 = board.read_voltage()@htf.measures( htf.Measurement("firmware_version").equals("2.1.0"), htf.Measurement("idle_current").in_range(0.05, 0.20).with_units(units.AMPERE),)@htf.plug(board=BoardPlug)def test_system(test, board): test.measurements.firmware_version = board.query_firmware() test.measurements.idle_current = board.read_current()def main(): test = htf.Test( test_power, test_system, procedure_id="FCT-001", part_number="PCBA-100", ) with TofuPilot(test): test.execute(test_start=lambda: input("Scan serial number: "))Every measurement flows into TofuPilot with limits, units, and pass/fail status. You get FPY, Cpk, and failure Pareto automatically.
Flying Probe
Flying probe machines use motorized probes that move to each test point. No fixture needed. The machine programs from your Gerber files and netlist.
What Flying Probe Catches
Same defects as ICT: shorts, opens, wrong values, missing components. Some machines add:
- Capacitance measurement
- Inductance measurement
- Boundary scan (JTAG) integration
- Basic functional tests (limited)
Flying Probe Costs
| Item | Typical Cost |
|---|---|
| Fixture | $0 (fixtureless) |
| Setup time | Hours (from Gerber + netlist) |
| Machine | $100,000-500,000 (capital) |
| Test time per board | 1-10 minutes (depends on test points) |
| Per-board cost at CM | $5-50 depending on program complexity |
When to Use Flying Probe
- Prototypes and first articles. Zero fixture cost, fast setup.
- Low volume (< 5K/year). Cheaper than ICT fixtures.
- Design iteration. No fixture to modify when the board changes.
- Complex BGAs. Some flying probe machines can test BGA pads via boundary scan.
When to Skip Flying Probe
- High volume. Too slow (1-10 minutes vs. 5-30 seconds for ICT).
- When you need FCT anyway. Flying probe doesn't replace FCT for system-level tests.
- Budget constraints at CM. Some contract manufacturers charge premium for flying probe time.
Test Strategy by Volume
| Volume (units/year) | Recommended Strategy | Why |
|---|---|---|
| 1-100 (prototype) | FCT only | Low volume, simple fixture, catches most defects |
| 100-1,000 | Flying probe + FCT | Flying probe catches assembly defects, FCT catches system issues |
| 1,000-10,000 | Flying probe or ICT + FCT | Evaluate ICT fixture ROI at upper end |
| 10,000-100,000 | ICT + FCT | ICT fixture pays for itself, fast test time |
| 100,000+ | AOI + ICT + FCT | Full coverage, maximum throughput |
Test Strategy by Board Complexity
| Board Complexity | Components | Recommended Tests |
|---|---|---|
| Simple (LED driver, sensor board) | < 50 | FCT only |
| Medium (MCU board, IoT device) | 50-200 | Flying probe + FCT |
| Complex (multi-rail, mixed signal) | 200-500 | ICT + FCT |
| Very complex (RF, high-speed digital) | 500+ | AOI + ICT + FCT + specialized |
Coverage Comparison
| Defect Type | AOI | ICT | Flying Probe | FCT |
|---|---|---|---|---|
| Missing component | Yes | Yes | Yes | Sometimes |
| Wrong value | No | Yes | Yes | Sometimes |
| Solder short | Yes | Yes | Yes | Sometimes |
| Cold solder joint | Yes | No | No | Sometimes |
| Tombstoning | Yes | No | No | No |
| Wrong polarity | No | Yes | Yes | Sometimes |
| Firmware bug | No | No | No | Yes |
| Power rail issue | No | No | No | Yes |
| Communication failure | No | No | No | Yes |
| Performance degradation | No | No | No | Yes |
No single test method catches everything. The combination of ICT (or flying probe) for assembly defects plus FCT for system defects gives you the best coverage.