# 题目链接

#include <bits/stdc++.h>
using namespace std;
#define mem(x,v) memset(x,v,sizeof(x))
const int N = 5e5 + 10;
struct node{
int b,next;
}g[N];
stack<int>q;
vector<int>f[N];
int dfn[N],low[N],times,cont,scc[N],d[N];
bool instk[N];
g[cnt].b = y;
return;
}

void tarjan(int u, int fa){
low[u] = dfn[u] = ++times;
q.push(u);
for (int i = head[u]; i; i = g[i].next){
int v = g[i].b;
if (v == fa) continue;
if (!dfn[v]) {
tarjan(v,u);
low[u] = min(low[u],low[v]);
} else low[u]= min(low[u],dfn[v]);
}
if (low[u] == dfn[u]){
cont++;
while(true){
int v = q.top(); q.pop();
scc[v] = cont;
if (v == u) break;
}
}
return;
}
void dfs(int x,int y){
d[x] = d[y]+1;
instk[x] = 1;
for (int i = 0; i < f[x].size(); i++)
if (f[x][i] != y && !instk[f[x][i]]) dfs(f[x][i],x);
return;
}
int main(){
int T,x,y;
cin>>T;
while(T--){
cnt = 0;
mem(g,0);
scanf("%d%d",&n,&m);
for (int i = 0; i < m; i++){
scanf("%d%d",&x,&y);
}
times = 0;
cont = 0;
while(!q.empty()) q.pop();
for (int i = 0; i <= n; i++){
low[i] = dfn[i] = scc[i] = 0;
}
tarjan(1,0);  //强联通。
for (int i = 0; i <= cont; i++)
f[i].clear();
for (int i = 1; i <= n; i++) //新建边。找树的直径。
for (int j = head[i]; j; j = g[j].next)
if (scc[i] != scc[g[j].b]){
f[scc[g[j].b]].push_back(scc[i]);
f[scc[i]].push_back(scc[g[j].b]);
}

int S = 0,ans = 0;

mem(instk,0);
dfs(1,0);
for (int i = 1; i <= cont; i++) if (d[i] > d[S]) S = i;
mem(instk,0);
dfs(S,0);
for (int i = 1; i <= cont; i++)
ans = max(ans,d[i]);
printf("%d\n",cont-ans);
}
return 0;
}